C# rows of multi-dimensional arrays
Asked Answered
C

3

8

In the C# programming language, how do I pass a row of a multi-dimensional array? For example, suppose I have the following:

int[,] foo;
foo = new int[6,4];
int[] least;
least = new int[6];

for(int i = 0; i < 6; i++)
{
    least[i] = FindLeast(ref foo[i]);     //How do I pass the ith row of foo???
}

Also, could anyone explain to me the benefit of having rectangular and jagged arrays in C#? Does this occur in other popular programming languages? (Java?) Thanks for all the help!

Coastal answered 6/3, 2012 at 19:2 Comment(0)
F
8

You can't pass a row of a rectangular array, you have to use a jagged array (an array of arrays):

int[][] foo = new int[6][];

for(int i = 0; i < 6; i++)
    foo[i] = new int[4];

int[] least = new int[6];

for(int i = 0; i < 6; i++)
    least[i] = FindLeast(foo[i]);

EDIT
If you find it so annoying to use a jagged array and desperately need a rectangular one, a simple trick will save you:

int FindLeast(int[,] rectangularArray, int row)
Favianus answered 6/3, 2012 at 19:7 Comment(3)
Can I pass a rectangular array to a function that accepts jagged arrays?Coastal
@CodeKingPlusPlus: No, you can'tFavianus
So basically this isn't a solution :)Limbo
L
4

You don't, with a rectangular array like that. It's a single object.

Instead, you'd need to use a jagged array, like this:

// Note: new int[6][4] will not compile
int[][] foo = new int[6][];
for (int i = 0; i < foo.Length; i++) {
    foo[i] = new int[4];
}

Then you can pass each "sub"-array:

int[] least = new int[foo.Length];
for(int i = 0; i < 6; i++)
{
    least[i] = FindLeast(foo[i]);
}

Note that there's no need to pass foo[i] by reference1, and also it's a good idea to assign local variables values at the point of declaration, when you can. (It makes your code more compact and simpler to understand.)


1 If you're not sure about this, you might want to read my article on parameter passing in C#.

Lindesnes answered 6/3, 2012 at 19:6 Comment(7)
You've beaten me by seconds! :PFavianus
Can I pass a rectangular array as a jagged array?Coastal
This, to me, seems like a non-solution. What can be done in the case of a rectangular array?Limbo
@NielsAbildgaard: Nothing, basically. The answer to the question is "you can't do that". It may not be an answer the OP wants to hear, but it's the correct answer.Lindesnes
@JonSkeet That's just not true. It might require more code and be cumbersome (which should be taken into account), but it is definitely possible.Limbo
@NielsAbildgaard: You can't pass it as an array, which is what the OP appeared to be looking for. You could create your own wrapper type, but there's no indication that that would help the OP. However, if you think you have a better answer, why not add it yourself?Lindesnes
@JonSkeet Just did ;)Limbo
L
-1

Update: As Jon Skeet rightly points out, this does not provide a reference to the row, but rather creates a new copy. If your code needs to change a row, this method doesn't work. I have renamed the method to make this clear.

Update 2: If you want to be able to edit the fields, and have the changes happen to the parent array, too, you can use the wrapper I provide in this library I maed. The resulting row foo.Row(i) is not an array, but instead implements IList, so if you need to pass an array this is not a solution, either.


This extension method will allow you to query a multi-dimensional array for rows. It should be noted that this is computationally heavy (not efficient) and if it is possible you should use a jagged array for these situations. If, however, you find yourself in a situation where you cannot use a jagged array, this might be useful.

public static T[] CopyRow<T>(this T[,] arr, int row)
{
    if (row > arr.GetLength(0))
        throw new ArgumentOutOfRangeException("No such row in array.", "row");

    var result = new T[arr.GetLength(1)];
    for (int i = 0; i < result.Length; i++)
    {
        result[i] = arr[row, i];
    }
    return result;
}

Your code can now be rewritten:

int[,] foo;
foo = new int[6,4];
int[] least;
least = new int[6];

for(int i = 0; i < 6; i++)
{
    least[i] = FindLeast(ref foo.CopyRow(i));
}
Limbo answered 2/5, 2014 at 13:49 Comment(8)
That's copying the array contents though, which doesn't do the same thing. In particular, if FindLeast modifies the array, then that modification won't be visible in the result. Additionally, the result of foo.Row(i) isn't classified as a variable, so the code won't compile. You simply can't treat a rectangular array as if it were a jagged array - arrays just don't work like that.Lindesnes
I do not understand your comment about compilation. The code runs and compiles.Limbo
You are absolutely right! This not passing a reference to a row (which cannot be done). Assuming that FindLeast does not modify the row, this should work. I will rename the method, though :)Limbo
It may solve the OP's FindLeast example, but it doesn't address the more general question of passing a single row of a rectangular array as a single-dimensional array, which is (as I keep saying) impossible.Lindesnes
It does pass a row. It doesn't pass a reference to the same row. It passes a copy of the row. I think we are in agreement about what C# can and cannot do. I disagree with whether or not reference passing is required for an answer to the original question :)Limbo
I think that is implicit, to be honest. "Pass a row of a multi-dimensional array" and "pass a copy of a row of a multi-dimensional array" are two different things. I think it's a lot clearer to say "You can't pass a row" than to claim that you can, and actually just pass a copy. I still maintain that the best answer to the OP's question is "you can't".Lindesnes
The "rewritten" code doesn't use your CopyRow method. It actually doesn't appear to be rewritten in any way. Also, the order of strings passed to the ArgumentOutOfRangeException constructor is wrong - the parameter name should come first.Whitehot
That was a simple typo -- (Row -> CopyRow). Fixed.Limbo

© 2022 - 2024 — McMap. All rights reserved.