1

I have two arrays:

T[] array1D;
T[,] array2D;

They each have the same total number of elements.

If these arrays had the same number of dimensions, then I could simply use Array.Copy to copy data from one to the other. But since they have differing numbers of dimensions, I cannot, according to the MSDN documentation:

The sourceArray and destinationArray parameters must have the same number of dimensions.

Having profiled my code, I have determined that copying each element individually is too slow for my purposes. So, is there an alternative to Array.Copy that can copy between arrays of differing dimensions with performance similar to that of Array.Copy?

Thank you!

(edit) As requested, here is my code for copying each element individually:

        int iMax = array2D.GetLength(0);
        int jMax = array2D.GetLength(1);
        int index = 0;
        for(int i = 0; i < iMax; ++i)
        {
            for(int j = 0; j < jMax; ++j)
            {
                array1D[index] = array2D[i, j];
                ++index;
            }
        }
Walt D
  • 4,491
  • 6
  • 33
  • 43
  • Post the code you are using to copy. Also consider wrapping an array where you just translate the number of dimension. – paparazzo Mar 30 '14 at 16:40
  • 2
    Have you tried [Buffer.BlockCopy](http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy%28v=vs.110%29.aspx) to flatten the 2-d array? Example code in [Jon Skeet's answer](http://stackoverflow.com/questions/5132397/fast-way-to-convert-a-two-dimensional-array-to-a-list-one-dimensional). – Andrew Morton Mar 30 '14 at 17:04
  • How hacky can the code be? You could use pointers, unsafe and raw memcpy... – Marc Gravell Mar 30 '14 at 17:08

2 Answers2

3

This should run faster than your code, not sure how much faster though. Let us know:

public static T[] FlattenArray<T>(T[,] array)
{
    List<T> values = new List<T>(array.Length);

    foreach (var item in array)
    {
        values.Add(item);
    }

    return values.ToArray();
}

EDIT:

This should be even faster. Anything quicker will likely need to be some unmanaged solution.

public static T[] FlattenArray<T>(T[,] array)
{
    T[] values = new T[array.Length];

    Buffer.BlockCopy(array, 0, values, 0, values.Length);

    return values;
}
Ashigore
  • 4,618
  • 1
  • 19
  • 39
  • Why not create an array directly? –  Mar 30 '14 at 17:11
  • @hvd Because then you can't do it with a foreach or else its pointless to because you have to increment the indexes which will result in code pretty much identical to the OPs solution. – Ashigore Mar 30 '14 at 17:14
  • You would only need a single index, rather than the three in the OP's code, so it could still well be an improvement. (`foreach (var item in array) values[index++] = item;`) Anyway, the overhead of first creating a list, filling it, then creating an array from that list is likely to be high enough that it's a worse solution than anything that creates an array directly. But your edit (which was mentioned in a comment on the question too) avoids that problem. –  Mar 30 '14 at 17:21
  • Shouldn't it be `Buffer.BlockCopy(array, 0, values, 0, values.Length * sizeof(T));`? – Grx70 Mar 30 '14 at 17:23
  • Thanks!! Buffer.BlockCopy works in my case, since T happens to be an unmanaged type. I'd still love to see an answer that works if T is a reference type. – Walt D Mar 30 '14 at 18:04
0

This may break as as not sure you can parallel a single object(array) like this
I tried with with a small number of elements and just string

I like the BlockCopy answer

private String[] ArrayCopy(String[,] array2D)
{
    int iMax = array2D.GetLength(0);
    int jMax = array2D.GetLength(1);
    String[] array1D = new String[iMax * jMax];
    for (int i = 0; i < iMax; ++i)
    {
        //System.Diagnostics.Debug.WriteLine("    parallel " + i.ToString());
        Parallel.For(0, jMax, j =>
        {
            //System.Diagnostics.Debug.WriteLine("  j loop parallel " + j.ToString() + " " + array2D[i,j]);
            array1D[(i * jMax) + j] = array2D[i, j];
        });
    }
    return array1D;
}
paparazzo
  • 44,497
  • 23
  • 105
  • 176