www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Fixed matrix rows joining

reply bearophile <bearophileHUGS lycos.com> writes:
If I have a simple fixed-size matrix and I need to linearize (flatten) it, the
function join() seems to not not work:


import std.array: join;
void main() {
    int[4][4] table;
    join(table);
}


test.d(4): Error: template std.array.join(RoR,R) if (isInputRange!(RoR) &&
isInputRange!(ElementType!(RoR)) && isForwardRange!(R) &&
is(Unqual!(ElementType!(ElementType!(RoR))) == Unqual!(ElementType!(R)))) does
not match any function template declaration
test.d(4): Error: template std.array.join(RoR,R) if (isInputRange!(RoR) &&
isInputRange!(ElementType!(RoR)) && isForwardRange!(R) &&
is(Unqual!(ElementType!(ElementType!(RoR))) == Unqual!(ElementType!(R))))
cannot deduce template function from argument types !()(int[4u][4u])


This too doesn't work:
join(table[]);



This compiles:
join(map!q{ a[] }(table[]));


But this program shows there is something wrong (I know what's wrong), it
prints:
[6, 4219787, 4, 6, 4219787, 4]


import std.stdio: writeln;
import std.algorithm: map;
import std.array: join;
void main() {
    int[3][2] table = [[1,2,3],[4,5,6]];
    int[] result = join(map!q{ a[] }(table[]));
    writeln(result);
}



This prints the right output, but it allocates lot of memory:
[1, 2, 3, 4, 5, 6]


import std.stdio: writeln;
import std.algorithm: map;
import std.array: join;
void main() {
    int[3][2] table = [[1,2,3],[4,5,6]];
    int[] result2 = join(map!q{ a.dup }(table[]));
    writeln(result2);
}


Do you have better suggestions?
Is the function join() worth fixing/changing to improve this use case?

Bye,
bearophile
Jan 14 2012
next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
A rectangular array is really just one array, is it not? From a syntax
point it looks like a multidimensional array but really it's just a
single linear piece of memory, so just cast it:

void main()
{
    int[2][4] table;
    table[0][] = 0;
    table[1][] = 1;
    table[2][] = 2;
    table[3][] = 3;
    auto x = cast(int[])table;
    assert(x == [0, 0, 1, 1, 2, 2, 3, 3]);
}
Jan 14 2012
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I guess join() could be specialized for static arrays and then just do
a dup and a cast? Would that work ok?
Jan 14 2012
parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 15/01/12 2:19 AM, Andrej Mitrovic wrote:
 I guess join() could be specialized for static arrays and then just do
 a dup and a cast? Would that work ok?

There should be no need to allocate extra memory to do this.
Jan 15 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/15/2012 02:38 AM, bearophile wrote:
 If I have a simple fixed-size matrix and I need to linearize (flatten) it, the
function join() seems to not not work:


 import std.array: join;
 void main() {
      int[4][4] table;
      join(table);
 }


 test.d(4): Error: template std.array.join(RoR,R) if (isInputRange!(RoR)&& 
isInputRange!(ElementType!(RoR))&&  isForwardRange!(R)&& 
is(Unqual!(ElementType!(ElementType!(RoR))) == Unqual!(ElementType!(R)))) does
not match any function template declaration
 test.d(4): Error: template std.array.join(RoR,R) if (isInputRange!(RoR)&& 
isInputRange!(ElementType!(RoR))&&  isForwardRange!(R)&& 
is(Unqual!(ElementType!(ElementType!(RoR))) == Unqual!(ElementType!(R))))
cannot deduce template function from argument types !()(int[4u][4u])


 This too doesn't work:
 join(table[]);



 This compiles:
 join(map!q{ a[] }(table[]));


 But this program shows there is something wrong (I know what's wrong), it
prints:
 [6, 4219787, 4, 6, 4219787, 4]


 import std.stdio: writeln;
 import std.algorithm: map;
 import std.array: join;
 void main() {
      int[3][2] table = [[1,2,3],[4,5,6]];
      int[] result = join(map!q{ a[] }(table[]));
      writeln(result);
 }



 This prints the right output, but it allocates lot of memory:
 [1, 2, 3, 4, 5, 6]


 import std.stdio: writeln;
 import std.algorithm: map;
 import std.array: join;
 void main() {
      int[3][2] table = [[1,2,3],[4,5,6]];
      int[] result2 = join(map!q{ a.dup }(table[]));
      writeln(result2);
 }


 Do you have better suggestions?

join(map!((int[] a)=>a)(table[])) although I'd like join(map!((ref a)=>a[])(table[])) to work. I'll file an enhancement.
 Is the function join() worth fixing/changing to improve this use case?

 Bye,
 bearophile

Jan 15 2012