Slicing 2D Arrays in D

If I have a 2D array in D, I know that I can create 1D fragments along the lines as follows:

auto one_dim_arr=two_dim_arr[i][0..$] 

Is there an easy way to do a 1D slice along the columns? Something that does what you might think

 auto one_dim_arr=two_dim_arr[0..$][j] 

will do?

+6
source share
3 answers

Here's what a custom type might look like for this:

 // Demo void main() { int[3][3] arr = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; // simple creation auto middleColumn = verticalSlice(arr, 1); assert(middleColumn[1] == 5); // iteratable foreach (i, v; middleColumn) assert(v == 2+i*3); // still a slice - writing will change original array middleColumn[1] = 17; assert(arr[1][1] == 17); // sliceable itself auto center = middleColumn[1..2]; center[0] = 42; assert(arr[1][1] == 42); // get a normal array with .dup int[] copyOfMiddleColumn = middleColumn.dup; } // Implementation struct StepSlice(T) { T* ptr; size_t length, step; T opIndex(size_t index) in { assert(index<length); } body { return ptr[step*index]; } void opIndexAssign(T value, size_t index) in { assert(index<length); } body { ptr[step*index] = value; } StepSlice!T opSlice(size_t start, size_t end) in { assert(start<=end && end<=length); } body { return StepSlice!T(ptr+start*step, end-start, step); } int opApply(int delegate(ref T) dg) { int result = 0; for (size_t i=0; i<length; i++) { result = dg(ptr[i*step]); if (result) break; } return result; } int opApply(int delegate(ref size_t, ref T) dg) { int result = 0; for (size_t i=0; i<length; i++) { result = dg(i, ptr[i*step]); if (result) break; } return result; } T[] dup() { T[] result = new T[length]; for (size_t i=0; i<length; i++) result[i] = ptr[i*step]; return result; } } StepSlice!T verticalSlice(T, size_t W)(T[W][] arr, size_t column) { return StepSlice!T(arr[0].ptr+column, arr.length, W); } 

I think these are the missing range primitives, but still a good starting point.


From std.range.stride :

 import std.range; // Demo void main() { int[3][3] arr = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; // simple creation auto middleColumn = verticalSlice(arr, 1); assert(middleColumn[1] == 5); // iteratable uint i; foreach (v; middleColumn) assert(v == 2+(i++)*3); // still a slice - writing will change original array middleColumn[1] = 17; assert(arr[1][1] == 17); // sliceable itself auto center = middleColumn[1..2]; center[0] = 42; assert(arr[1][1] == 42); // get a normal array with array() int[] copyOfMiddleColumn = array(middleColumn); } // Implementation auto verticalSlice(T, size_t W)(T[W][] arr, size_t column) { T* start = arr[0].ptr+column; return stride(start[0..W*arr.length], W); } 
+4
source

No, It is Immpossible. For this to work, D slices will need to complete the step. You can create a custom type that works similar to a slice (for example, std.algorithm.map).

Note that your suggested syntax above will compile fine, but does not have the effect you are looking for.

+3
source

If your input is T[][] (that is, a dynamic array of dynamic arrays), and you want it to be the same as the output, you can select a new "external" array and fill it with slices of internal arrays. This will lead to O(n) op, where O(1) op is used as the normal slice. Coding remains as an exercise for the reader.

+2
source

Source: https://habr.com/ru/post/890964/


All Articles