views:

1655

answers:

5

We have the following object

int [,] oGridCells;

which is only used with a fixed first index

int iIndex = 5;
for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
{
  //Get the value from the 2D array
  iValue = oGridCells[iIndex, iLoop];

  //Do something with iValue
}

Is there a way in .NET to convert the values at a fixed first index into a single dimension array (other than by looping the values)?

I doubt it would speed up the code (and it may well make it slower) if the array is only being looped once. But if the array was being heavily manipulated then a single dimension array would be more efficient than a multi dimension array.

My main reason for asking the question is to see if it can be done and how, rather than using it for production code.

A: 

I'd be suprised if it were possible: I bet oGridCells[iIndex, iLoop] is just a sort of shorthand (internally, in MSIL) for oGridCells[iIndex * iLoop], and that multidimensional arrays are syntactic sugar for this.

To answer your question: No. You will have to loop the values.

Daren Thomas
They are a different type to single dimension arrays. A zero index single dimension array is a vector type while all other arrays are array type. So not syntax sugar.
Stevo3000
A: 

Edit:

I realized there is a way! Granted, it's probably not worth it. Use unsafe code. Full example, showing both ways, with unsafe below:

public class MultiSingleUnsafe
{
    public static unsafe void Main(String[] a)
    {
    int rowCount = 6;
    int iUpperBound = 10;
    int [,] oGridCells = new int[rowCount, iUpperBound];

    int iIndex = rowCount - 2; // Pick a row.

    for(int i = 0; i < iUpperBound; i++)
    {
        oGridCells[iIndex, i] = i;
    }

    for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
    {
        //Get the value from the 2D array
        int iValue = oGridCells[iIndex, iLoop];
        Console.WriteLine("Multi-dim array access iValue: " + iValue);
        //Do something with iValue
    }

    fixed(int *lastRow = &(oGridCells[iIndex,0]))
    { 
        for (int iLoop = 0; iLoop < iUpperBound; iLoop++)
        {
     int iValue = lastRow[iLoop];
     Console.WriteLine("Pointer access iValue: " + iValue);
        }
    }
    }
}

There is no way I know to cast a multiple-dimensional array into a single-dimensional one in C#. Of course, you could create a new single-dimensional array and copy into it. But I don't think this will get a performance benefit even if you loop over the values multiple times. As Daren said, internally it's all pointer arithmetic anyway. If you want to be certain, profile it.

Matthew Flaschen
I'm not looking for a cast, I know that that is not possible.
Stevo3000
+1  A: 

The following code demonstrates copying 16 bytes (4 ints) from a 2-D array to a 1-D array.

int[,] oGridCells = {{1, 2}, {3, 4}};
int[] oResult = new int[4];
System.Buffer.BlockCopy(oGridCells, 0, oResult, 0, 16);

You can also selectively copy just 1 row from the array by providing the correct byte offsets. This example copies the middle row of a 3-row 2-D array.

int[,] oGridCells = {{1, 2}, {3, 4}, {5, 6}};
int[] oResult = new int[2];
System.Buffer.BlockCopy(oGridCells, 8, oResult, 0, 8);
BlueMonkMN
This doesn't acheive the results required as it copies all the values, not just the values from first index 0 or 1.
Stevo3000
I added an example to copy 1 row.
BlueMonkMN
To use this method you would need to calculate the bounds of the array to get the offset. This something that is inefficient for multi dimension arrays. But it does look like it would work.
Stevo3000
What's inefficient about it? The size of the element times the number of elements per row times the row index is the offset. And you only have to calculate the offset once if your row index doesn't change.
BlueMonkMN
Agreed, I guess that you would have to call the inefficient method to find the upper bounds to be able to loop through the elements as in the question source code. Your code doesn't look quite right though, your array is int [2, 3] so one row of data would be int[3] at either index 0 or 1.
Stevo3000
As demonstrated by "Console.WriteLine("{0} {1}", oGridCells[0, 1], oGridCells[1, 0]);" the first index refers to the row number and the second index refers to the column number. My array is int[3,2], you have to declare it as int[,] oGridCells = new int[3,2] { { 1, 2 }, { 3, 4 }, { 5, 6 } };. If you try to use 2,3 you get an error.
BlueMonkMN
Hey, this is exactly the answer you asked for isn't it? Have you checked it out?
BlueMonkMN
No this is not what I asked for. I want all the column values for a single row, as the question code shows by using a fixed first index.
Stevo3000
That's what this does. Have you tried it?
BlueMonkMN
Yes it does do what I asked, I miss read the code.
Stevo3000
+1  A: 

You cannot get a reference to each array. You can, however, use a jagged array.

Groo
Agreed, if I was re-writing the code (which is not an option) I would make use of jagged arrays. Especially as jagged arrays have an improved performance over multi dimension arrays.
Stevo3000
+1  A: 

"But if the array was being heavily manipulated then a single dimension array would be more efficient than a multi dimension array."

I did some profiling of exactly this last summer and was surprised to see no significant difference in performance between a 2D and 1D array.

I didn't test the performance of a jagged array.

AnnaR
They are different types, certain operations (e.g. testing the length) can be significantly slower. A jagged array offers the best of both worlds.
Stevo3000