Collapsing n-dimensional array to linear (1 dimensional)
Solomon E via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sun Jan 24 18:27:57 PST 2016
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)
.array)
.array)
.array;
assert(r3.equal(r3i));
}
void main() {
}
More information about the Digitalmars-d-learn
mailing list