www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Assigning to slice of array

reply Jamie <jamieborder01 gmail.com> writes:
I'm trying to understand arrays and have read a lot of the 
information about them on this forum. I think I understand that 
they are set-up like Type[], so that int[][] actually means an 
array of int[].

I create an array as per the following:
     auto arr = new int[3][2][1];
which produces:
     [[0, 0, 0], [0, 0, 0]]
(for each of the following assignments, assume that the array is 
set back to zeros)

and I can change the 2nd element of the 1st array using:
     arr[0][1] = 4;
which produces:
     [[0, 4, 0], [0, 0, 0]]

and I can change the entire 1st array using:
     arr[0][0 .. 3] = 5;
which produces:
     [[5, 5, 5], [0, 0, 0,]]

however when I try and change elements across arrays rather than 
within arrays my understanding breaks down.. when I try
     arr[0 .. 2][0] = 3;   // which I think is equivalent to 
arr[0][0] and arr[1][0]
I'm expecting:
     [[3, 0, 0], [3, 0, 0]]
but it produces:
     [[3, 3, 3], [0, 0, 0]]
showing that arr[0][0 .. 2] is making the same index as arr[0 .. 
3][0] ?

Instead of using [0 .. 2] I can use the actual indices to get the 
result I desired:
     arr[0][0] = 3;
     arr[1][0] = 3;
which produces:
     [[3, 0, 0], [3, 0, 0]]

Could I just get some help with understanding how the slice [0 .. 
2] actually works? Thanks
Mar 01 2018
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/1/18 4:16 PM, Jamie wrote:
 I'm trying to understand arrays and have read a lot of the information 
 about them on this forum. I think I understand that they are set-up like 
 Type[], so that int[][] actually means an array of int[].
 
 I create an array as per the following:
      auto arr = new int[3][2][1];
 which produces:
      [[0, 0, 0], [0, 0, 0]]
No, I think you did int[3][2], if you got that output. Otherwise it would have been: [[[0,0,0],[0,0,0]]] Looking at the rest of your code, I think it wouldn't work if you had done the line above.
 (for each of the following assignments, assume that the array is set 
 back to zeros)
 
 and I can change the 2nd element of the 1st array using:
      arr[0][1] = 4;
 which produces:
      [[0, 4, 0], [0, 0, 0]]
 
 and I can change the entire 1st array using:
      arr[0][0 .. 3] = 5;
 which produces:
      [[5, 5, 5], [0, 0, 0,]]
Yes, all correct.
 
 however when I try and change elements across arrays rather than within 
 arrays my understanding breaks down..
Well, that's because that type of slicing isn't supported directly. You can't slice an array cross-wise like that. You may be interested in ndslice inside mir: http://docs.algorithm.dlang.io/latest/mir_ndslice.html
 when I try
      arr[0 .. 2][0] = 3;   // which I think is equivalent to arr[0][0] 
Consider the array: int[] x = new int[2]; Now, what would the slice x[0 .. 2] be? That's right, the same as x. So when you slice arr[0 .. 2], it's basically the same as arr (as arr has 2 elements). So arr[0 .. 2][0] is equivalent to arr[0]. One thing that is interesting is that you assigned 3 to an array, and it wrote it to all the elements. I did not know you could do that with static arrays without doing a proper slice assign. But it does compile (I learn something new every day). -Steve
Mar 01 2018
parent reply Jamie <jamieborder01 gmail.com> writes:
On Thursday, 1 March 2018 at 21:31:49 UTC, Steven Schveighoffer 
wrote:
 No, I think you did int[3][2], if you got that output. 
 Otherwise it would have been:

 [[[0,0,0],[0,0,0]]]
Yes apologies that was there from a previous attempt, you are correct.
 Well, that's because that type of slicing isn't supported 
 directly. You can't slice an array cross-wise like that.

 You may be interested in ndslice inside mir: 
 http://docs.algorithm.dlang.io/latest/mir_ndslice.html
Thanks I've just had a quick read and this looks promising for what I want (similar functionality to numpy), but I also want to understand arrays.
 when I try
      arr[0 .. 2][0] = 3;   // which I think is equivalent to 
 arr[0][0]
Consider the array: int[] x = new int[2]; Now, what would the slice x[0 .. 2] be? That's right, the same as x. So when you slice arr[0 .. 2], it's basically the same as arr (as arr has 2 elements). So arr[0 .. 2][0] is equivalent to arr[0].
So if I do arr[0 .. 1][0] = 3; shouldn't this return [[3, 0, 0], [0, 0, 0]] ? Because I'm taking the slice arr[0 .. 1], or arr[0], which is the first [0, 0, 0]? Then assigning the first element to 3? instead it returns [[3, 3, 3], [0, 0, 0]]
 One thing that is interesting is that you assigned 3 to an 
 array, and it wrote it to all the elements. I did not know you 
 could do that with static arrays without doing a proper slice 
 assign. But it does compile (I learn something new every day).

 -Steve
Well I'm learning a lot today :)
Mar 01 2018
parent reply ag0aep6g <anonymous example.com> writes:
On 03/01/2018 11:43 PM, Jamie wrote:
 So if I do
      arr[0 .. 1][0] = 3;
 shouldn't this return
      [[3, 0, 0], [0, 0, 0]] ? Because I'm taking the slice arr[0 .. 1], 
 or arr[0], which is the first [0, 0, 0]?
arr[0 .. 1] is not the same as arr[0]. arr[0 .. 1] is not the first element of arr; it's an array that contains the first element of arr. It's not [0, 0, 0]; it's [[0, 0, 0]]. It's not an int[]; it's an int[][].
 Then assigning the first 
 element to 3?
 instead it returns
      [[3, 3, 3], [0, 0, 0]]
Since arr[0 .. 1] is [[0, 0, 0]], arr[0 .. 1][0] is [0, 0, 0]. Assigning 3 to that means assigning to all of its values. And so you get [3, 3, 3].
Mar 01 2018
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/1/18 5:59 PM, ag0aep6g wrote:
 On 03/01/2018 11:43 PM, Jamie wrote:
 So if I do
      arr[0 .. 1][0] = 3;
 shouldn't this return
      [[3, 0, 0], [0, 0, 0]] ? Because I'm taking the slice arr[0 .. 
 1], or arr[0], which is the first [0, 0, 0]?
arr[0 .. 1] is not the same as arr[0]. arr[0 .. 1] is not the first element of arr; it's an array that contains the first element of arr. It's not [0, 0, 0]; it's [[0, 0, 0]]. It's not an int[]; it's an int[][].
Minor correction, it's actually an int[3][]. Try arr[1 .. 2][0] = 3; It will affect the second static array. I understand what you really want is the first element of each static array. There is no supported syntax for arrays to slice like that. This is where ndslice comes in. But if it *were* supported, it would look like this instead (I think this is how ndslice would work, but I've never used it): arr[0 .. 2, 0] = 3; The thing I think you are missing is that the expression stops at the closing bracket. In other words arr[0 .. 2][0] is really (arr[0 .. 2])[0]. arr[0 .. 2] is a slice of the original array, which happens to be the entire array. So it really doesn't get you anything. One final note. If you don't want to use array assignment operators, and don't mind using ranges, you can do what you want this way: https://run.dlang.io/is/AdikEE -Steve
Mar 02 2018
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, March 01, 2018 21:16:54 Jamie via Digitalmars-d-learn wrote:
 I'm trying to understand arrays and have read a lot of the
 information about them on this forum. I think I understand that
 they are set-up like Type[], so that int[][] actually means an
 array of int[].

 I create an array as per the following:
      auto arr = new int[3][2][1];
 which produces:
Don't put the indices within the brackets. What you want is auto arr = new int[][][](3, 2, 1); With a new expression, unless you only have one dimension, you end up with dynamic arrays of static arrays. e.g. if you use what I wrote there with pragma(msg, typeof(arr).stringof); it prints int[][][] whereas with what you wrote, you get int[3][2][] which is a dynamic array of a static array of length 2 of static arrays of int of length 3 rather than a dynamic array of a dynamic array of a dynamic array of ints. Unfortunately, auto arr = new int[5]; and auto arr = new int[](5); are equivalent, so dealing with just single dimension arrays does not prepare you properly for dealing with multi-dimensional arrays. Arguably, it would have been better to just force using the parens, though that would make the most common case more verbose, so it's debatable. - Jonathan M Davis
Mar 01 2018
parent reply Jamie <jamieborder01 gmail.com> writes:
On Thursday, 1 March 2018 at 21:34:41 UTC, Jonathan M Davis wrote:
 Don't put the indices within the brackets. What you want is

 auto arr = new int[][][](3, 2, 1);
Okay thanks, but I don't understand what is the issue with having static arrays there instead? My functionality didn't change when I replaced the single line with your line? And I couldn't resize either of them with array.length, which is also something I would like. Thanks
Mar 01 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, March 01, 2018 22:57:16 Jamie via Digitalmars-d-learn wrote:
 On Thursday, 1 March 2018 at 21:34:41 UTC, Jonathan M Davis wrote:
 Don't put the indices within the brackets. What you want is

 auto arr = new int[][][](3, 2, 1);
Okay thanks, but I don't understand what is the issue with having static arrays there instead? My functionality didn't change when I replaced the single line with your line? And I couldn't resize either of them with array.length, which is also something I would like. Thanks
static arrays have a fixed size, so you can't resize them with any operation - including setting their length. Static arrays are value types, so when they're copied, the whole thing is copied, whereas with a dynamic array is just a pointer and a length, so copying it just slices the dynamic array to give you another dynamic array. It's just copying the pointer and the length. A dynamic array is effectively struct DynamicArray(T) { size_t length; T* ptr; } whereas a static array is an actual buffer that sits wherever it's declared (on the stack if it's a local variable). So, something like auto arr = new int[][][](3, 2, 1); arr.length = 4; arr[0].length = 5; arr[0][0].length = 6; is legal, but something like auto arr = new int[3][2][1]; arr.length = 4; // this one is still legal, since it's a dynamic array arr[0].length = 5; arr[0][0].length = 6; is not legal. - Jonathan M Davis
Mar 01 2018
parent reply Jamie <jamieborder01 gmail.com> writes:
On Thursday, 1 March 2018 at 23:17:11 UTC, Jonathan M Davis wrote:
 So, something like

 auto arr = new int[][][](3, 2, 1);
 arr.length = 4;
 arr[0].length = 5;
 arr[0][0].length = 6;

 is legal, but something like
Thanks Jonathan, this is exactly what I was looking for. I was getting confused with not being able to resize because I was looking at int[] arrays and I guess the way I was defining them caused them both to be dynamic (when I thought one was static). On a similar not, is there an accepted way to assign across arrays? As Steve mentioned, cross-slicing isn't supported, so is the best way to iterate through the array and assign as necessary? Thanks, Jamie
Mar 01 2018
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, March 01, 2018 23:51:37 Jamie via Digitalmars-d-learn wrote:
 On a similar not, is there an accepted way to assign across
 arrays? As Steve mentioned, cross-slicing isn't supported, so is
 the best way to iterate through the array and assign as necessary?
That's what you would have to do. You're basically dealing with stuff like int*** except that it also has its length with it and wraps it in a nicer way, and so each of these buffers that you're dealing with are essentially unrelated. They just have a common root. Even if there were some sort of high level operation that did something along the lines of what you're looking for, it would pretty much have to lower to something along the lines of what you'd be doing to solve the problem on your own. It's not like these are these are buffers which are somehow squares or cubes in memory such that they you could slice along a different dimension. They're still just linear buffers of memory. - Jonathan M Davis
Mar 01 2018