Thread overview
Why are 2-D arrays reversed?
Oct 10, 2018
Chris Katko
Oct 10, 2018
Mike Parker
Oct 10, 2018
Chris Katko
Oct 11, 2018
Jonathan M Davis
October 10, 2018
int[][] data =
	[
		[1, 0, 1, 0, 0],
		[1, 0, 1, 0, 0],
		[1, 0, 1, 1, 1],
		[1, 0, 0, 1, 0],
		[5, 1, 1, 1, 0]
	];

when drawn with data[i][j], prints the transpose of "data":

[1, 1, 1, 1, 5]
[0, 0, 0, 0, 1]
[1, 1, 1, 0, 1]
[0, 0, 1, 1, 1]
[0, 0, 1, 0, 0]

So, if I flip [i][j] and print a row of "j's", it'll be correct. It's very confusing and counter-intuitive to have to remember to swap i and j every time I use an array.

I guess when I load data from files, the i/j are already swapped and stay consistent, but when using an array in source code, they have to be flipped.
October 10, 2018
On Wednesday, 10 October 2018 at 13:22:41 UTC, Chris Katko wrote:
> int[][] data =
> 	[
> 		[1, 0, 1, 0, 0],
> 		[1, 0, 1, 0, 0],
> 		[1, 0, 1, 1, 1],
> 		[1, 0, 0, 1, 0],
> 		[5, 1, 1, 1, 0]
> 	];
>
> when drawn with data[i][j], prints the transpose of "data":
>
> [1, 1, 1, 1, 5]
> [0, 0, 0, 0, 1]
> [1, 1, 1, 0, 1]
> [0, 0, 1, 1, 1]
> [0, 0, 1, 0, 0]
>
> So, if I flip [i][j] and print a row of "j's", it'll be correct. It's very confusing and counter-intuitive to have to remember to swap i and j every time I use an array.
>
> I guess when I load data from files, the i/j are already swapped and stay consistent, but when using an array in source code, they have to be flipped.

What you actually have there is an array of arrays, or a jagged array, and not a 2D, or multidimensional, array. If you dig into it, it's consistent with how array syntax works with all types. Consider the basics:

int i;
int[] intArray;

The type of `i` is `int`. If I want an array of ints, I put the brackets next to the type.

The type of `intArray` is `int[]`, but it contains elements of type `int`. We can visualize it with parens:

(int)[];

This indicates that `int` is the element type. We can apply the same rules to int[][]:

int[] singleArr;    // type is int[], element type int
int[][] doubleArr;  // type is int[][], element type ?

Again, using parens we cans the element type of `doubleArr`:

(int[])[];

So singleArr[0] returns the first `int`, and doubleArr[][0] returns the first int[]. Consistent.

So the syntax you are used to in C or C++ is /backwards/ in D.






October 10, 2018
On 10/10/18 9:22 AM, Chris Katko wrote:
> int[][] data =
>      [
>          [1, 0, 1, 0, 0],
>          [1, 0, 1, 0, 0],
>          [1, 0, 1, 1, 1],
>          [1, 0, 0, 1, 0],
>          [5, 1, 1, 1, 0]
>      ];
> 
> when drawn with data[i][j], prints the transpose of "data":
> 
> [1, 1, 1, 1, 5]
> [0, 0, 0, 0, 1]
> [1, 1, 1, 0, 1]
> [0, 0, 1, 1, 1]
> [0, 0, 1, 0, 0]
> 
> So, if I flip [i][j] and print a row of "j's", it'll be correct. It's very confusing and counter-intuitive to have to remember to swap i and j every time I use an array.
> 
> I guess when I load data from files, the i/j are already swapped and stay consistent, but when using an array in source code, they have to be flipped.

I'm not sure what code you are using, but it prints out just fine for me:

https://run.dlang.io/is/hrA0tj

-Steve
October 10, 2018
On Wednesday, 10 October 2018 at 16:00:42 UTC, Steven Schveighoffer wrote:
> On 10/10/18 9:22 AM, Chris Katko wrote:
>> int[][] data =
>>      [
>>          [1, 0, 1, 0, 0],
>>          [1, 0, 1, 0, 0],
>>          [1, 0, 1, 1, 1],
>>          [1, 0, 0, 1, 0],
>>          [5, 1, 1, 1, 0]
>>      ];
>> 
>> when drawn with data[i][j], prints the transpose of "data":
>> 
>> [1, 1, 1, 1, 5]
>> [0, 0, 0, 0, 1]
>> [1, 1, 1, 0, 1]
>> [0, 0, 1, 1, 1]
>> [0, 0, 1, 0, 0]
>> 
>> So, if I flip [i][j] and print a row of "j's", it'll be correct. It's very confusing and counter-intuitive to have to remember to swap i and j every time I use an array.
>> 
>> I guess when I load data from files, the i/j are already swapped and stay consistent, but when using an array in source code, they have to be flipped.
>
> I'm not sure what code you are using, but it prints out just fine for me:
>
> https://run.dlang.io/is/hrA0tj
>
> -Steve

Ah, here's a simple example:

int[][] data3 =
	[
		[1, 0, 1, 0, 0],
		[1, 0, 1, 0, 0],
		[1, 0, 1, 1, 1],
		[1, 0, 0, 1, 0],
		[5, 1, 1, 1, 0]
	];

	for(int i = 0; i < 5; i++)
		{
		for(int j = 0; j < 5; j++)
			{
			write(data4[i][j]," ");
			}
		writeln();
		}

  1 0 1 0 0
  1 0 1 0 0
  1 0 1 1 1
  1 0 0 1 0
  5 1 1 1 0

I have to draw j's first. I have to iterate through the "y"/columns/j to get the the "x's" first.

I mean, I guess it makes sense if the outer-most array indexer refers to the inner-most "element".

Wait, this IS the same as C, isn't it? So maybe this is just a "new" problem for me since I rarely-if-ever use hardcoded arrays...

Maybe my brain is just melting.
October 10, 2018
On Wednesday, October 10, 2018 4:26:40 PM MDT Chris Katko via Digitalmars-d- learn wrote:
> On Wednesday, 10 October 2018 at 16:00:42 UTC, Steven
>
> Schveighoffer wrote:
> > On 10/10/18 9:22 AM, Chris Katko wrote:
> >> int[][] data =
> >>
> >>      [
> >>          [1, 0, 1, 0, 0],
> >>          [1, 0, 1, 0, 0],
> >>          [1, 0, 1, 1, 1],
> >>          [1, 0, 0, 1, 0],
> >>          [5, 1, 1, 1, 0]
> >>      ];
> >>
> >> when drawn with data[i][j], prints the transpose of "data":
> >>
> >> [1, 1, 1, 1, 5]
> >> [0, 0, 0, 0, 1]
> >> [1, 1, 1, 0, 1]
> >> [0, 0, 1, 1, 1]
> >> [0, 0, 1, 0, 0]
> >>
> >> So, if I flip [i][j] and print a row of "j's", it'll be correct. It's very confusing and counter-intuitive to have to remember to swap i and j every time I use an array.
> >>
> >> I guess when I load data from files, the i/j are already swapped and stay consistent, but when using an array in source code, they have to be flipped.
> >
> > I'm not sure what code you are using, but it prints out just fine for me:
> >
> > https://run.dlang.io/is/hrA0tj
> >
> > -Steve
>
> Ah, here's a simple example:
>
> int[][] data3 =
>   [
>       [1, 0, 1, 0, 0],
>       [1, 0, 1, 0, 0],
>       [1, 0, 1, 1, 1],
>       [1, 0, 0, 1, 0],
>       [5, 1, 1, 1, 0]
>   ];
>
>   for(int i = 0; i < 5; i++)
>       {
>       for(int j = 0; j < 5; j++)
>           {
>           write(data4[i][j]," ");
>           }
>       writeln();
>       }
>
>    1 0 1 0 0
>    1 0 1 0 0
>    1 0 1 1 1
>    1 0 0 1 0
>    5 1 1 1 0
>
> I have to draw j's first. I have to iterate through the "y"/columns/j to get the the "x's" first.
>
> I mean, I guess it makes sense if the outer-most array indexer refers to the inner-most "element".
>
> Wait, this IS the same as C, isn't it? So maybe this is just a "new" problem for me since I rarely-if-ever use hardcoded arrays...
>
> Maybe my brain is just melting.

The situation is bascially the same as C, though trying to make the type syntax more consistent by putting it all on the left-hand side of the variable has made things more confusing. The types read basically the same as in C. The primary difference is that in D, the static array sizes go with the type and not the variable name, which means that they're on the left-hand side rather than the right. So, you get

int[5][4] arr;

instead of

int arr[4][5];

In both cases, the type is read outward from the variable name (which is basically how the compiler reads types in both C and D, though understanding that is more critical in C because of C's function pointer syntax). It's just that in the D case, this then seems backwards, because when you then index the array, the left index has $ of 4 and the right has $ of 5, which is the reverse of the order in the declaration, whereas in C, the order matches, because the sizes went on the right-hand side. One sort of consistency was traded for another. With dynamic arrays, the sizes are always given on the right-hand side, so you don't get that reversal. So, what D does is reasonably consistent and matches C in terms of how types are read, but it does end up being annoyingly hard to wrap your head around, because the result is that the sizes of multi-dimensional, static arrays are then declared in the opposite order from the order that they're accessed in. If it weren't for the fact that D does out-of-bounds checking for all array accesses in @safe code or when -release is not used, it would likely to be a huge problem with such arrays in practice. Fortunately, since the checks are almost always in place, the inevitable mistakes are usually quickly caught.

- Jonathan M Davis



October 11, 2018
On 10/10/18 6:26 PM, Chris Katko wrote:

> Wait, this IS the same as C, isn't it? So maybe this is just a "new" problem for me since I rarely-if-ever use hardcoded arrays...

Yes, I think that is right. The only difference is if you specify a NON-square array, D requires you specify in the opposite order from how you will index (as Jonathan said). In C you specify in the same order.

But for square arrays (dynamic or otherwise), I think it works exactly the same.

To me, the D way is more consistent and easier to explain because of the consistency. Any time you see T[], whether T is some basic type or an array itself, then you have an array of Ts. So int[5][4] is an array of 4 int[5]'s

> Maybe my brain is just melting.

It is recovering from using C ;)

-Steve