Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-25 Thread ixid via Digitalmars-d-learn

On Monday, 25 January 2016 at 08:31:14 UTC, abad wrote:

On Monday, 25 January 2016 at 02:27:57 UTC, Solomon E wrote:

On Saturday, 23 January 2016 at 07:57:55 UTC, Ali Çehreli
Ruby's Array class includes this sort method for flattening and 
for me it was surprisingly useful, for instance when it was 
necessary to write the array to file.


D could certainly add a few more helper functions to work on 
multidimensional data or perhaps an article, I admit I was 
unaware joiner could be chained without mapping like that. One 
that regularly irritates me is arrays of results that you want to 
make eager such that you can map a lazy function to a 2D array 
and then store the result in a 2D array again. This seems messy 
and I'd like a function that will take absolutely anything and 
force eager assessment.


auto a = res.map!array.array; // De-lazying 2D result

Would like:

auto a = res.eager;


Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-25 Thread abad via Digitalmars-d-learn

On Monday, 25 January 2016 at 02:27:57 UTC, Solomon E wrote:

On Saturday, 23 January 2016 at 07:57:55 UTC, Ali Çehreli wrote:


auto collapse(R)(R r)
if (isArray!R) {
return r.joiner.collapse.joiner;
}

auto collapse(R)(R r)
if (!isArray!R) {
return r;
}



Ali, that code only passed the one test it had for collapsing a 
three level array. It wouldn't collapse arrays of other numbers 
of levels. It wasn't recursing as appeared to be intended.


Is the following code better D? (I don't know because I'm still 
learning D, so I'd like to be corrected if the comments in my 
code are inaccurate or misleading.)


(See https://issues.dlang.org/show_bug.cgi?id=12062 for where I 
got the idea that `flatten` should be defined to mutate by 
reference. A comment there suggests to use 
std.experimental.ndslice and byElement for that, but ndlslice 
doesn't seem to be in the library anymore.)




I will give this a try later.

Ruby's Array class includes this sort method for flattening and 
for me it was surprisingly useful, for instance when it was 
necessary to write the array to file.


I will also take a look at ndslice and see how intuitive its 
approach for achieving this would be.




Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-24 Thread Solomon E via Digitalmars-d-learn

On Saturday, 23 January 2016 at 07:57:55 UTC, Ali Çehreli wrote:


auto collapse(R)(R r)
if (isArray!R) {
return r.joiner.collapse.joiner;
}

auto collapse(R)(R r)
if (!isArray!R) {
return r;
}



Ali, that code only passed the one test it had for collapsing a 
three level array. It wouldn't collapse arrays of other numbers 
of levels. It wasn't recursing as appeared to be intended.


Is the following code better D? (I don't know because I'm still 
learning D, so I'd like to be corrected if the comments in my 
code are inaccurate or misleading.)


(See https://issues.dlang.org/show_bug.cgi?id=12062 for where I 
got the idea that `flatten` should be defined to mutate by 
reference. A comment there suggests to use 
std.experimental.ndslice and byElement for that, but ndlslice 
doesn't seem to be in the library anymore.)



import std.stdio;
import std.range;
import std.algorithm;
import std.traits;

/** `collapse` returns an array that can be type inferred
 *  and can be cast to [] without effect
 */

auto collapse(R)(R r)
if (isArray!(ElementType!R)) {
return r.joiner.array.collapse;
}

auto collapse(R)(R r)
if (!isArray!(ElementType!R)) {
return r;
}

/** `flatten` returns a range Result that can modify the original 
by ref

 * and .flatten.array is equivalent to .collapse
 */

auto flatten(R)(R r)
if (isIterable!R && isIterable!(ElementType!R)) {
return r.joiner.flatten;
}

auto flatten(R)(R r)
if (!(isIterable!R && isIterable!(ElementType!R))) {
return r;
}

unittest {
auto r1 = 3.iota.array;
auto r2 = 3.iota.map!(i => iota(3 * i, 3 * i + 
3).array).array;

assert(r2 == [[0,1,2],[3,4,5],[6,7,8]]);
auto r3 = 3.iota
.map!(i => iota(3 * i, 3 * i + 3)
.map!(j => iota(3 * j, 3 * j + 3)
.array)
.array)
.array;
auto r4 = 3.iota
.map!(i => iota(3 * i, 3 * i + 3)
.map!(j => iota(3 * j, 3 * j + 3)
.map!(j => iota(3 * j, 3 * j + 3)
.array)
.array)
.array)
.array;
auto r5 = 3.iota
.map!(i => iota(3 * i, 3 * i + 3)
.map!(j => iota(3 * j, 3 * j + 3)
.map!(j => iota(3 * j, 3 * j + 3)
.map!(j => iota(3 * j, 3 * j 
+ 3)

.array)
.array)
.array)
.array)
.array;

writeln("\nOriginal 1 level:\n", r1);
writeln("Collapsed:\n", r1.collapse);

writeln("\nOriginal 2 level:\n", r2);
writeln("Collapsed:\n", r2.collapse);

writeln("\nOriginal 3 level:\n", r3);
writeln("Collapsed:\n", r3.collapse);

writeln("\nOriginal 4 level:\n", r4);
writeln("Collapsed:\n", r4.collapse);

writeln("\nOriginal 5 level:\n", r5);
writeln("Collapsed:\n", r5.collapse);

// equality (collapse is eager and iota is lazy)
assert(r1.collapse.equal(iota(3)));
assert(r2.collapse.equal(iota(9)));
assert(r3.collapse.equal(iota(27)));
assert(r4.collapse.equal(iota(81)));
assert(r5.collapse.equal(iota(243)));

// value equality
assert(r1.collapse == iota(3).array);
assert(r2.collapse == iota(9).array);
assert(r3.collapse == iota(27).array);
assert(r4.collapse == iota(81).array);
assert(r5.collapse == iota(243).array);

// cast is allowed and does not affect the result
assert(cast(int[]) r1.collapse == iota(3).array);
assert(cast(int[]) r2.collapse == iota(9).array);
assert(cast(int[]) r3.collapse == iota(27).array);
assert(cast(int[]) r4.collapse == iota(81).array);
assert(cast(int[]) r5.collapse == iota(243).array);

// type inference
auto ar1 = r1.collapse;
assert(ar1 == iota(3).array);
auto ar2 = r2.collapse;
assert(ar2 == iota(9).array);
auto ar3 = r3.collapse;
assert(ar3 == iota(27).array);
auto ar4 = r4.collapse;
assert(ar4 == iota(81).array);
auto ar5 = r5.collapse;
assert(ar5 == iota(243).array);

// lazy equality
assert(r1.flatten.equal(iota(3)));
assert(r2.flatten.equal(iota(9)));
assert(r3.flatten.equal(iota(27)));
assert(r4.flatten.equal(iota(81)));
assert(r5.flatten.equal(iota(243)));

// equivalence between .flatten.array and .collapse
assert(r1.flatten.array == ar1);
assert(r2.flatten.array == ar2);
assert(r3.flatten.array == ar3);
assert(r4.flatten.array == ar4);
assert(r5.flatten.array == ar5);

// mutation by reference through a flatten
foreach (ref x; r3.flatten) {
x++;
}
writeln("r3 scalar incremented ", r3);
auto r3i = iota(1, 4)
.map!(i => iota(3 * i - 2, 3 * i + 1)
.map!(j => iota(3 * j - 2, 3 * j + 1)
 

Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-23 Thread Ali Çehreli via Digitalmars-d-learn

On 01/22/2016 04:07 AM, abad wrote:

Let's say I have an array like this:

int[][][] array;

And I want to generate a linear int[] based on its data. Is there a
standard library method for achieving this, or must I iterate over the
array manually?

What I'm thinking of is something like this:

int[] onedim = std.array.collapse(array);




Something feels extra down there but it seems to work. :)

import std.stdio;
import std.range;
import std.algorithm;

auto collapse(R)(R r)
if (isArray!R) {
return r.joiner.collapse.joiner;
}

auto collapse(R)(R r)
if (!isArray!R) {
return r;
}

unittest {
auto r = 3.iota
 .map!(i => iota(3 * i, 3 * i + 3)
.map!(j => iota(3 * j, 3 * j + 3)
   .array)
.array)
 .array;

writeln("Original:\n", r);
writeln("\nCollapsed:\n", r.collapse);
assert(r.collapse.equal(iota(27)));
}

void main() {
}

Original:
[[[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[9, 10, 11], [12, 13, 14], [15, 16, 
17]], [[18, 19, 20], [21, 22, 23], [24, 25, 26]]]


Collapsed:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
20, 21, 22, 23, 24, 25, 26]


Ali



Collapsing n-dimensional array to linear (1 dimensional)

2016-01-22 Thread abad via Digitalmars-d-learn

Let's say I have an array like this:

int[][][] array;

And I want to generate a linear int[] based on its data. Is there 
a standard library method for achieving this, or must I iterate 
over the array manually?


What I'm thinking of is something like this:

int[] onedim = std.array.collapse(array);




Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-22 Thread NX via Digitalmars-d-learn

On Friday, 22 January 2016 at 12:07:11 UTC, abad wrote:

Let's say I have an array like this:

int[][][] array;

And I want to generate a linear int[] based on its data. Is 
there a standard library method for achieving this, or must I 
iterate over the array manually?


What I'm thinking of is something like this:

int[] onedim = std.array.collapse(array);


It's not the thing you want but I would suggest using one 
dimensional array like N dimensional array like this:


int d1 = 10, d2 = 10, d3 = 10;
int[] arr = new int[d1 * d2 * d3];
for(int i = 0; i < d1; i++)
for(int j = 0; j < d2; j++)
for(int k = 0; k < d3; k++)
write(arr[(i * d1 * d2) + (j * d2) + (k)]);

This will lead to cache friendly code in most cases as you ensure 
data is packed. It's elements can be iterated with a single 
foreach loop and easier to use in some (many?) cases like when 
using functions that works with one dimensional array.


And if you seriously need multi dimensional array then it's too 
easier to do it yourself:


int[][][] a = new int[][][](d1, d2, d3);
int[] collapsed = new int[d1 * d2 * d3];
foreach(i, q; a)
foreach(j, w; q)
foreach(k, e; w)
collapsed[(i * d1 * d2) + (j * d2) + (k)] = e;


Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-22 Thread Xinok via Digitalmars-d-learn

On Friday, 22 January 2016 at 12:07:11 UTC, abad wrote:

Let's say I have an array like this:

int[][][] array;

And I want to generate a linear int[] based on its data. Is 
there a standard library method for achieving this, or must I 
iterate over the array manually?


What I'm thinking of is something like this:

int[] onedim = std.array.collapse(array);


You can use std.algorithm.joiner but you have to call it twice to 
flatten a 3D array to a 1D array.


import std.algorithm, std.stdio, std.array;

void main()
{
int[][][] arr = [[[1], [2, 3]], [[4, 5], [6, 7]], [[8], 
[9, 10], [11]]];

int[] arr2 = arr.joiner.joiner.array;
writeln(arr);
writeln(arr2);
}

http://dlang.org/phobos/std_algorithm_iteration.html#.joiner


Re: Collapsing n-dimensional array to linear (1 dimensional)

2016-01-22 Thread Ilya via Digitalmars-d-learn

On Friday, 22 January 2016 at 12:07:11 UTC, abad wrote:

Let's say I have an array like this:

int[][][] array;

And I want to generate a linear int[] based on its data. Is 
there a standard library method for achieving this, or must I 
iterate over the array manually?


What I'm thinking of is something like this:

int[] onedim = std.array.collapse(array);


You may want to look at upcoming Multidimensional Random Access 
Ranges, `std.experimental.ndslice` package. They are available 
with DMD 2.070 beta.


Pacakge has `reshape` and `byElement` functions.

Docs: 
http://dlang.org/phobos-prerelease/std_experimental_ndslice.html


Ilya