views:

2264

answers:

4

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

+4  A: 

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.

Mehrdad Afshari
Is there a way I can initialize my jagged array without using a for ? I mean something like : double[][] jaggedArray = new double[100][100]; ?
Melursus
No, essentially, you are building an array of `double[]` objects. Those objects are totally unrelated to the original array.
Mehrdad Afshari
A: 

A jagged array would let you split out the first array!

Stevo3000
+6  A: 

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();
Joel Coehoorn
This is certainly a better solution if the problem calls for a real multidimensional array and not a jagged one.
mquander
A: 

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;      
}
Iceman