Method that accepts both float[] and double[] arrays - c#

I have a method that accepts an array (float or double), start and end index and then does some element manipulations for indexes in startIndex to endIndex range.
Basically it looks like this:
public void Update(float[] arr, int startIndex, int endIndex)
{
if (condition1)
{
//Do some array manipulation
}
else if (condition2)
{
//Do some array manipulation
}
else if (condition3)
{
if (subcondition1)
{
//Do some array manipulation
}
}
}
Method is longer than this, and involves setting some elements to 0 or 1, or normalizing the array.
The problem is that I need to pass both float[] and double[] arrays there, and don't want to have a duplicated code that accepts double[] instead.
Performance is also critical, so I don't want to create a new double[] array, cast float array to it, perform calcs, then update original array by casting back to floats.
Is there any solution to it that avoids duplicated code, but is also as fast as possible?

You have a few options. None of them match exactly what you want, but depending on what kind of operations you need you might get close.
The first is to use a generic method where the generic type is restricted, but the only operations you can do are limited:
public void Update<T>(T[] arr, int startIndex, int endIndex) : IComarable
{
if (condition1)
{
//Do some array manipulation
}
else if (condition2)
{
//Do some array manipulation
}
else if (condition3)
{
if (subcondition1)
{
//Do some array manipulation
}
}
}
And the conditions and array manipulation in that function would be limited to expressions that use the following forms:
if (arr[Index].CompareTo(arr[OtherIndex])>0)
arr[Index] = arr[OtherIndex];
This is enough to do things like find the minimum, or maximum, or sort the items in the array. It can't do addition/subtraction/etc, so this couldn't, say, find the average. You can make up for this by creating your own overloaded delegates for any additional methods you need:
public void Update<T>(T[] arr, int startIndex, int endIndex, Func<T,T> Add) : IComarable
{
//...
arr[Index] = Add(arr[OtherIndex] + arr[ThirdIndex]);
}
You'd need another argument for each operation that you actually use, and I don't know how that will perform (that last part's gonna be a theme here: I haven't benchmarked any of this, but performance seems to be critical for this question).
Another option that came to mind is the dynamic type:
public void Update(dynamic[] arr, int startIndex, int endIndex)
{
//...logic here
}
This should work, but for something called over and over like you claim I don't know what it would do to the performance.
You can combine this option with another answer (now deleted) to give back some type safety:
public void Update(float[] arr, int startIndex, int endIndex)
{
InternalUpdate(arr, startIndex, endIndex);
}
public void Update(double[] arr, int startIndex, int endIndex)
{
InternalUpdate(arr, startIndex, endIndex);
}
public void InternalUpdate(dynamic[] arr, int startIndex, int endIndex)
{
//...logic here
}
One other idea is to cast all the floats to doubles:
public void Update(float[] arr, int startIndex, int endIndex)
{
Update( Array.ConvertAll(arr, x => (double)x), startIndex, endIndex);
}
public void Update(double[] arr, int startIndex, int endIndex)
{
//...logic here
}
Again, this will re-allocate the array, and so if that causes a performance issue we'll have to look elsewhere.
If (and only if) all else fails, and a profiler shows that this is a critical performance section of your code, you can just overload the method and implement the logic twice. It's not ideal from a code maintenance standpoint, but if the performance concern is well-established and documented, it can be the worth the copy pasta headache. I included a sample comment to indicate how you might want to document this:
/******************
WARNING: Profiler tests conducted on 12/29/2014 showed that this is a critical
performance section of the code, and that separate double/float
implementations of this method produced a XX% speed increase.
If you need to change anything in here, be sure to change BOTH SETS,
and be sure to profile both before and after, to be sure you
don't introduce a new performance bottleneck. */
public void Update(float[] arr, int startIndex, int endIndex)
{
//...logic here
}
public void Update(double[] arr, int startIndex, int endIndex)
{
//...logic here
}
One final item to explore here, is that C# includes a generic ArraySegment<T> type, that you may find useful for this.

Just an idea. I have no idea what the performance implications are, but this helped me to go to sleep :P
public void HardcoreWork(double[] arr){HardcoreWork(arr, null);}
public void HardcoreWork(float[] arr){HardcoreWork(null, arr);}
public struct DoubleFloatWrapper
{
private readonly double[] _arr1;
private readonly float[] _arr2;
private readonly bool _useFirstArr;
public double this[int index]
{
get {
return _useFirstArr ? _arr1[index] : _arr2[index];
}
}
public int Length
{
get {
return _useFirstArr ? _arr1.Length : _arr2.Length;
}
}
public DoubleFloatWrapper(double[] arr1, float[] arr2)
{
_arr1 = arr1;
_arr2 = arr2;
_useFirstArr = _arr1 != null;
}
}
private void HardcoreWork(double[] arr1, float[] arr2){
var doubleFloatArr = new DoubleFloatWrapper(arr1, arr2);
var len = doubleFloatArr.Length;
double sum = 0;
for(var i = 0; i < len; i++){
sum += doubleFloatArr[i];
}
}
Don't forget that if the amount of elements you have is ridiculously small, you can just use pooled memory, which will give you zero memory overhead.
ThreadLocal<double[]> _memoryPool = new ThreadLocal<double[]>(() => new double[100]);
private void HardcoreWork(double[] arr1, float[] arr2){
double[] array = arr1;
int arrayLength = arr1 != null ? arr1.Length : arr2.Length;
if(array == null)
{
array = _memoryPool.Value;
for(var i = 0; i < arr2.Length; i++)
array[i] = arr2[i];
}
for(var i = 0; i < 1000000; i++){
for(var k =0; k < arrayLength; k++){
var a = array[k] + 1;
}
}
}

What about implementing the method using generics? An abstract base class can be created for your core business logic:
abstract class MyClass<T>
{
public void Update(T[] arr, int startIndex, int endIndex)
{
if (condition1)
{
//Do some array manipulation, such as add operation:
T addOperationResult = Add(arr[0], arr[1]);
}
else if (condition2)
{
//Do some array manipulation
}
else if (condition3)
{
if (subcondition1)
{
//Do some array manipulation
}
}
}
protected abstract T Add(T x, T y);
}
Then implement per data type an inheriting class tuned to type-specific operations:
class FloatClass : MyClass<float>
{
protected override float Add(float x, float y)
{
return x + y;
}
}
class DoubleClass : MyClass<double>
{
protected override double Add(double x, double y)
{
return x + y;
}
}

John's comment about macros, although completely inaccurate characterization of C++ templates, got me thinking about the preprocessor.
C#'s preprocessor is nowhere near as powerful as C's (which C++ inherits), but it still is able to handle everything you need except the duplication itself:
partial class MyClass
{
#if FOR_FLOAT
using Double = System.Single;
#endif
public void Update(Double[] arr, int startIndex, int endIndex)
{
// do whatever you want, using Double where you want the type to change, and
// either System.Double or double where you don't
}
}
Now, you need to include two copies of the file in your project, one of which has an extra
#define FOR_FLOAT
line at the top. (Should be fairly easy to automate adding that)
Unfortunately, the /define compiler option applies to the entire assembly, not per-file, so you can't use a hardlink to include the file twice and have the symbol only defined for one. However, if you can tolerate the two implementations being in different assemblies, you can include the same source file into both, using the project options to define FOR_FLOAT in one of them.
I still advocate using templates in C++/CLI.

Most code isn't so performance-critical that taking the time to convert from float to double and back causes a problem:
public void Update(float[] arr, int startIndex, int endIndex)
{
double[] darr = new double[arr.Length];
for(int i=startIndex; i<endIndex; i++)
darr[i] = (double) arr[i];
Update(darr, startIndex, endIndex);
for(int j=startIndex; j<endIndex; j++)
arr[j] = darr[j];
}
Here's a thought experiment. Imagine that instead of copying, you duplicated the code of the double[] version to make a float[] version. Imagine that you optimized the float[] version as much as necessary.
Your question is then: does the copying really take that long? Consider that instead of maintaining two versions of the code, you could spend your time improving the performance of the double[] version.
Even if you had been able to use generics for this, it's possible that the double[] version would want to use different code from the float[] version in order to optimize performance.

Related

How to modify loop into recursion if we need to use index as a condition?

Let's say we want to implement a sum algorithm I use C# as an illustration here:
// Iterative
int sum(int[] array) {
int result = 0;
foreach(int item in array) {
result += item;
}
return item;
}
which is equivalent to
// Recursive
int sum(int[] array) {
if(array.Length == 0) {
return 0;
}
// suppose there is a SubArray function here
return array[0] + sum(array.SubArray(1));
}
However, if we want to add a condition to the algorithm where we don't want to add the integer at index 2 to our result, we only need to add one conditional statement to our first (iterative) implementation.
Q: Is there any adaptation to our recursive one to make it work?
The recursive version is inefficient due to the repeated SubArray calls, making the time complexity O(n2). You can re-write this function to accept an additional index parameter, which also happens to be how you can implement skipping a particular index (or set of indices, if you choose).
In C#:
private static int SumSkipIndex(int[] arr, int skip, int i)
{
if (i >= arr.Length) return 0;
return (i == skip ? 0 : arr[i]) + SumSkipIndex(arr, skip, i + 1);
}
If you don't like the added i parameter which changes the function header, just write a separate private recursive "helper" function that can be called from the wrapper with your preferred header.
I'm also assuming you don't wish to hardcode index 2 into the algorithm (if you do, remove the skip parameter and replace i == skip with i == 2).
using System;
class MainClass
{
private static int SumSkipIndex(int[] arr, int skip, int i)
{
if (i >= arr.Length) return 0;
return (i == skip ? 0 : arr[i]) + SumSkipIndex(arr, skip, i + 1);
}
public static int SumSkipIndex(int[] arr, int skip)
{
return SumSkipIndex(arr, skip, 0);
}
public static void Main(string[] args)
{
Console.WriteLine(SumSkipIndex(new int[]{16, 11, 23, 3}, 1)); // => 42
}
}
Lastly, bear in mind that recursion is a terrible choice for this sort of algorithm (summing an array), even with the index version. We have to call a new function just to handle one number, meaning we have a lot of call overhead (allocating stack frames) and can easily blow the stack if the list is too long. But I'm assuming this is just a learning exercise.
A consise solution can be done in C# 8 using array slices.
public static int SumArray(int[] arr, int exclude){
if(arr.Length == 0){
return 0;
}
return (exclude==0?0:arr[0]) + SumArray(arr[1..], exclude-1);
}
The ternary operator checks if the skip index is 0, and if it isn't it will decrement the skip index for the next recursive call. The array is reduced using the slice, which should be more performant than SubArray. (Someone fact check me on the latter)
EDIT: As the other answer has suggested, this causes a bloating of stack frames due to a lack of tail call recursion. The below solution would mitigate the issue by using tail call optimisation, adding the sum variable to the function instead. This means the recursive call can use the same stack frame rather than creating a new one to await the return value before completing the sum.
public static int SumArray(int[] arr, int exclude, int sum=0){
if(arr.Length == 0){
return sum;
}
return SumArray(arr[1..], exclude-1, sum + (exclude==0?0: arr[0]));
}

Passing the dimension of an Array as a Parameter in C#

I'm learning C# and am trying to implement a versatile RandomVar class along with some methods for computing common statistics as practice. I'd like to be able form the arbitrary Joint probability RandomVariable from its components by instantiating a new variable of dimension N where N is passed into the constructor. I'd like to implement random Var X as two one dimensional lists of doubles, and the randomVar XY not as two lists of length n^2, but as a randomVar of type double[][] which otherwise can still use all of the same methods (ExpectedValue, Covariance, etc).
I'm having a lot of trouble implementing this. Other than the first naive approach (which had lots of copy and pasting), I've tried inheriting from a base RandomVar class into a JointRandomVar class -- still a lot of copy-pasting. Now I'm trying to the probabilities and outcomes arrays of Class RandomVar as Generics of type List -- this however produces a lot of problems as I can't figure out how to write the methods in an adaptable way (The std_Dev method can't iterate over the way it needs to in general -- so I need some flexible way to define the method so that if the "dimension" of the random Var is 2, the std_Dev method will do a double loop, or flatten out the array for the process of iterating).
Wanting some design help from more experienced programmers -- is having the probabilities/outcomes arrays List the best way to pass a parameter like this?
Thank you very much for your assistance.
EDIT: Here is the the version of the code for all doubles, so people can read it since the un-updated version seemed more confusing to people. I'd like to be able to have all of these methods work on objects of type double[] for any dimension of array, and it to be possible to instantiate the class with _values and _probs having any dimension.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Chapter_3_GUI
{
class RandomVar
{
private double[] _values;
private double[] _probs;
private double _mean;
private double _stddev;
private int _length;
private double _evalue;
public RandomVar(double[] values, double[] probs)
{
_values = values;
_probs = probs;
_mean = meanCalc(_values);
_stddev = stddevCalc(_values, _mean);
_length = _values.Length;
_evalue = expectedVal(_probs, _values, _length);
}
public double[] Values
{
get { return _values; }
set { _values = value; }
}
public double Mean
{
get { return _mean; }
}
public double Stdev
{
get { return _stddev; }
}
public static double meanCalc(double[] var)
{
double mean = var.Sum();
return mean;
}
public static double stddevCalc(double[] var, double mean)
{
double[] varianceArr = new double[var.Length];
for (int i = 0; i <= var.Length; i++)
varianceArr[i] = (var[i] - mean) * (var[i] - mean);
double variance = varianceArr.Sum();
double stddev = Math.Sqrt(variance);
return stddev;
{
}
}
public static double[][] multiplyProbs(RandomVar X, RandomVar Y, double[][] cprobMatrix)
{
double[][] probArr = new double[X._length][Y._length];
for (int i=0; i <= probArr.Length; i++)
{
for (int j =0; j <= probArr.Length; j++)
{
probArr[i][j] = Y._probs[j] * cprobMatrix[i][j];
}
}
return probArr;
}
public static RandomVar multiplyVars(RandomVar X, RandomVar Y, Func<double,double> f)
{
double[][] productArr = new double[X._length][Y._length];
for (int i=0; i<= productArr.Length; i++)
{
for (int j=0; j <= productArr.Length; i=j++)
{
productArr[i][j] = f(X._values[i], Y._values[j]);
}
}
double[][] probArr = multiplyProbs(X, Y, cprobMatrix);
RandomVar product = new RandomVar(productArr, probArr);
return product;
}
public static double expectedVal(double[] _probs, double[] _values, int _length)
{
double[] expectedArr = new double[_length];
for (int i = 0; i <= expectedArr.Length; i++)
{
expectedArr[i] = _probs[i] * _values[i];
}
double evalue = expectedArr.Sum();
return evalue;
}
public static double covarianceCalc(RandomVar X, RandomVar Y, Func<double, double> f)
{
RandomVar VarXY = multiplyVars(X, Y, f);
double correlation = expectedVal(VarXY._probs, VarXY._values, VarXY._length);
double covariance = correlation - (X._mean * Y._mean);
return covariance;
}
}
}
Is the cardinality of each dimension going to be the same? Your comment about "treating it as one long array of size n^k" suggests it is. That is, n is the length of value/probability pairs in each dimension.
The other question I have is, what is the reasoning behind passing the values and probabilities in two different arrays? If it were me, I'd declare a struct that contains the pairs, e.g.:
struct ValueProbPair
{
public readonly double Value;
public readonly double Probability;
public ValueProbPair(double value, double probability)
{
Value = value;
Probability = probability;
}
}
Finally, as far as your specific question goes…well, it's not clear what the specific question is. You seem to have a broad question regarding a flexible way to implement this.
It seems to me that the biggest challenge here (i.e. the roadblock with the least intuitively obvious solution) is in the title of your question:
Passing the dimension of an Array as a Parameter
You can do this, i.e. create an appropriate array object, by using the Array.CreateInstance(Type, int[]) overload. IMHO, it will also work better if (but is not required that) you can consolidate the value/probability pairs into a single struct.
The other big caveat is that you won't get the benefit of compiler optimizations for accessing array elements. You'll have to use e.g. the GetValue() method, which will most likely prevent the compiler from accessing array elements directly (the optimization is theoretically possible, but seems unlikely to me).
So, for example, you could do something like:
Array Combine(ValueProbPair[] newDimension, Array previousDimensions)
{
int[] rankLengths = new int[previousDimensions.Rank + 1];
for (int j = 0; j < previousDimensions.Rank; j++)
{
rankLengths[j] = previousDimensions.GetLength(j);
}
rankLengths[previousDimensions.Rank] = newDimension.Length;
Array result = Array.CreateInstance(typeof(ValueProbPair), rankLengths);
// then fill in your matrix using GetValue and SetValue to
// access individual array elements...
// Finally, return the new multi-dimensional array:
return result;
}
The various array method overloads that access elements use params array parameters, so you can without too much difficulty write code that can handle matrices of arbitrary dimension. E.g.:
IEnumerable<double> GetAllValues(Array source)
{
int[] index = new int[source.Rank];
while (true)
{
yield return (double)source.GetValue(index);
int j = 0;
while (++index[j] == source.GetLength(j))
{
index[j] = 0;
if (++j == index.Length)
{
yield break;
}
}
}
}
One last note: for dealing with value/probability, depending on your scenario you might actually find it makes more sense to do all this using dictionaries. There are different complications, but the basic building block would be Dictionary<double, object>, where the value is either double or another Dictionary<double, object>. Then if you are looking for e.g. a combined probability, you don't have to scan lists of values, but rather can just look them up directly as the key in the dictionary.

C# Add value to array through user input

I want to add elements to my array through a user input.
I know this can be done very easy using a list but i have to use an array.
The problem with the code is that the array.lenght will always be 1.
I want the array to have the same size as the total amount of elements in it, so
size of the array shouldnt be set when declaring the array.
I thought that if you add an element to an array it will copy the previous values + the added value and create a new array.
UPDATED WITH ANSWER
public static void Add(int x){
if (Item == null) // First time need to initialize your variable
{
Item = new int[1];
}
else
{
Array.Resize<int>(ref Item, Item.Length + 1);
}
Item[Item.Length-1] = x; //fixed Item.Length -> Item.Length-1
}
Use List<int> instead of an explicit array, which will dynamically size for you, and use the Add() method to add elements at the end.
I didn't test in VS. Here you go:
namespace ConsoleApplication1
{
class Program
{
static int[] Item; //Fixed int Item[] to int[] Item
static void Main(string[] args)
{
Add(3);
Add(4);
Add(6);
}
public static void Add(int x){
if (Item == null) // First time need to initialize your variable
{
Item = new int[1];
}
else
{
Array.Resize<int>(ref Item, Item.Length + 1);
}
Item[Item.Length-1] = x; //fixed Item.Length -> Item.Length-1
}
}
}
This should resize your array by one each time and then set the last item to what you are trying to add. Note that this is VERY inefficient.
Lists grow as you add elements to it. Arrays have a constant size. If you must use arrays, the easiest way to do it, is to create an array that is big enough to hold the entered elements.
private int[] _items = new int[100];
private int _count;
public void Add(int x)
{
_items[_count++] = x;
}
You also need to keep track of the number of elements already inserted (I used the field _count here);
As an example, you can then enumerate all the items like this:
for (int i = 0; i < _count; i++) {
Console.WriteLine(_items[i]);
}
You can make the items accessible publicly like this:
public int[] Items { get { return _items; } }
public int Count { get { return _count; } }
UPDATE
If you want to grow the array size automatically, this is best done by doubling the actual size, when the array becomes too small. It's a good compromise between speed and memory efficiency (this is how lists work internally).
private int[] _items = new int[8];
private int _count;
public void Add(int x)
{
if (_count == _items.Lengh) {
Array.Resize(ref _items, 2 * _items.Length);
}
_items[_count++] = x;
}
However, keep in mind that this changes the array reference. So no permanent copy of this array reference should be stored anywhere else.

Reading in a binary file containing an unknown quantity of structures (C#)

Ok, so I currently have a binary file containing an unknown number of structs like this:
private struct sTestStruct
{
public int numberOne;
public int numberTwo;
public int[] numbers; // This is ALWAYS 128 ints long.
public bool trueFalse;
}
So far, I use the following to read all the structs into a List<>:
List<sTestStruct> structList = new List<sTestStruct>();
while (binReader.BaseStream.Position < binReader.BaseStream.Length)
{
sTestStruct temp = new sTestStruct();
temp.numberOne = binReader.ReadInt32();
temp.numberTwo = binReader.ReadInt32();
temp.numbers = new int[128];
for (int i = 0; i < temp.numbers.Length; i++)
{
temp.numbers[i] = binReader.ReadInt32();
}
temp.trueFalse = binReader.ReadBoolean();
// Add to List<>
structList.Add(temp);
}
I don't really want to do this, as only one of the structs can be displayed to the user at once, so there is no point reading in more than one record at a time. So I thought that I could read in a specific record using something like:
fileStream.Seek(sizeof(sTestStruct) * index, SeekOrigin.Begin);
But it wont let me as it doesn't know the size of the sTestStruct, the structure wont let me predefine the array size, so how do I go about this??
The sTestStruct is not stored in one consecutive are of memory and sizeof(sTestStruct) is not directly related to the size of the records in the file. The numbers members is a reference to an array which you allocate youself in your reading code.
But you can easily specify the record size in code since it is a constant value. This code will seek to the record at index. You can then read one record using the body of your loop.
const Int32 RecordSize = (2 + 128)*sizeof(Int32) + sizeof(Boolean);
fileStream.Seek(RecordSize * index, SeekOrigin.Begin);
If you have many different fixed sized records and you are afraid that manually entering the record size for each record is error prone you could devise a scheme based on reflection and custom attributes.
Create an attribute to define the size of arrays:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
sealed class ArraySizeAttribute : Attribute {
public ArraySizeAttribute(Int32 length) {
Length = length;
}
public Int32 Length { get; private set; }
}
Use the attribute on your record type:
private struct sTestStruct {
public int numberOne;
public int numberTwo;
[ArraySize(128)]
public int[] numbers; // This is ALWAYS 128 ints long.
public bool trueFalse;
}
You can then compute the size of the record using this sample code:
Int32 GetRecordSize(Type recordType) {
return recordType.GetFields().Select(fieldInfo => GetFieldSize(fieldInfo)).Sum();
}
Int32 GetFieldSize(FieldInfo fieldInfo) {
if (fieldInfo.FieldType.IsArray) {
// The size of an array is the size of the array elements multiplied by the
// length of the array.
var arraySizeAttribute = (ArraySizeAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(ArraySizeAttribute));
if (arraySizeAttribute == null)
throw new InvalidOperationException("Missing ArraySizeAttribute on array.");
return GetTypeSize(fieldInfo.FieldType.GetElementType())*arraySizeAttribute.Length;
}
else
return GetTypeSize(fieldInfo.FieldType);
}
Int32 GetTypeSize(Type type) {
if (type == typeof(Int32))
return 4;
else if (type == typeof(Boolean))
return 1;
else
throw new InvalidOperationException("Unexpected type.");
}
Use it like this:
var recordSize = GetRecordSize(typeof(sTestStruct));
fileStream.Seek(recordSize * index, SeekOrigin.Begin);
You will probably have to expand a little on this code to use it in production.
From everything I have read, the way you are doing it is the best method to read in binary data as it has the fewest gotchas where things can go wrong.
Define your struct like this:
struct sTestStruct
{
public int numberOne;
public int numberTwo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)]
public int[] numbers; // This is ALWAYS 128 ints long.
public bool trueFalse;
}
And use Marshal.Sizeof(typeof(sTestStruct)).

c# array function argument pass one dimension

Let say I got this function :
void int Calculate(double[] array) {}
And in my main I got this array:
double[,] myArray = new double[3,3];
How can I call Calculate(...) ?
I try (that's don't compile) :
double[] mySingleArray = myArray[0];
What I want to avoid is unnecessary loop (for).
I declare a regular array, but if a jagged array or any other type of array works better, it's fine for me.
I use c# 3.5
First, let's declare your Calculate() method like this:
int Calculate(IEnumerable<double> doubles)
Don't worry, you can still pass an array to that code. You might also need IList<double>, but 9 times out of 10 the IEnumerable is good enough. The main thing is that this will let us use the yield keyword to slice up your array in an efficient way:
public static IEnumerable<T> Slice(this T[,] values)
{
return Slice(values, 0, 0);
}
public static IEnumerable<T> Slice(this T[,] values, int index)
{
return Slice(values, 0, index);
}
public static IEnumerable<T> Slice(this T[,] values, int dimension, int index)
{
int length = values.GetUpperBound(dimension);
int[] point = new int[values.Rank];
point[dimension] = index;
dimension = 1 - dimension;// only works for rank == 2
for (int i = 0; i < length; i++)
{
point[dimension] = i;
yield return (T)values.GetValue(point);
}
}
It still needs some work because it only works with rank 2 arrays, but it should be fine for the example you posted.
Now you can call your calculate function like this:
Calculate(myArray.Slice(0));
Note that due to the way IEnumerable and the yield statement work the for loop in the code I posted is essentially free. It won't run until you actually iterate the items in your Calculate method, and even there runs in a "just-in-time" fashion so that the whole algorithm remains O(n).
It gets even more interesting when you share what your Calculate method is doing. You might be able to express it as a simple Aggregate + lambda expression. For example, let's say your calculate method returned the number of items > 5:
myArray.Slice(0).Count(x => x > 5);
Or say it summed all the items:
myArray.Slice().Sum();
A jagged array works the way you want:
double[][] jaggedArray = new double[][100];
for (int i = 0; i < jaggedArray.Length; ++i)
jaggedArray[i] = new double[100];
myFunction(jaggedArray[0]);
You can have different sizes for each array in this way.
A jagged array would let you split out the first array!
The Slice() method given above will get you a single row from your array, which seems to match the sample given in your question.
However, if you want a one dimensional array that contains all the elements in the rectangular array, you can use something like this, which is also O(n).
public static T[] Flatten<T>(this T[,] array)
where T : struct
{
int size = Marshal.SizeOf(array[0, 0]);
int totalSize = Buffer.ByteLength(array);
T[] result = new T[totalSize / size];
Buffer.BlockCopy(array, 0, result, 0, totalSize);
return result;
}

Categories