Thread overview
From [Tuple!(A,B), ...] to Tuple!(A[], B[])
Feb 17, 2020
foozzer
Feb 17, 2020
Simen Kjærås
Feb 17, 2020
FeepingCreature
Feb 17, 2020
Simen Kjærås
Feb 17, 2020
Simen Kjærås
Feb 17, 2020
foozzer
February 17, 2020
Hi all,

There's something in Phobos for that?

Thank you
February 17, 2020
On Monday, 17 February 2020 at 11:07:33 UTC, foozzer wrote:
> Hi all,
>
> There's something in Phobos for that?
>
> Thank you

import std.meta : staticMap;
import std.typecons : Tuple;

// Turn types into arrays
alias ToArray(T) = T[];
// Leave everything else the same
alias ToArray(T...) = T;
// Now apply the above to each element of the Tuple template args:
alias ToArrayTuple(T : Tuple!U, U...) = Tuple!(staticMap!(ToArray, U));

unittest {
    alias A = Tuple!(int, string);
    assert(is(ToArrayTuple!A == Tuple!(int[], string[])));
    alias B = Tuple!(int, "a", string, "b");
    assert(is(ToArrayTuple!B == Tuple!(int[], "a", string[], "b")));
}

--
  Simen
February 17, 2020
On Monday, 17 February 2020 at 11:07:33 UTC, foozzer wrote:
> Hi all,
>
> There's something in Phobos for that?
>
> Thank you

Here you go:

import std;

// extract the types that make up the tuple
auto transposeTuple(T : Tuple!Types[], Types...)(T tuples)
{
    // templated function that extracts the ith field of an array of tuples as an array
    auto extractArray(int i)()
    {
        return tuples.map!(a => a[i]).array;
    }
    // return tuple of calls to extractArray, one for each tuple index
    return tuple(staticMap!(extractArray, aliasSeqOf!(Types.length.iota)));
}

void main() {
    Tuple!(int, double)[] array;
    array ~= tuple(1, 2.0);
    array ~= tuple(3, 4.0);
    Tuple!(int[], double[]) tuple = array.transposeTuple;
    assert(tuple[0] == [1, 3]);
    assert(tuple[1] == [2.0, 4.0]);
}
February 17, 2020
On Monday, 17 February 2020 at 11:51:52 UTC, FeepingCreature wrote:
> On Monday, 17 February 2020 at 11:07:33 UTC, foozzer wrote:
>> Hi all,
>>
>> There's something in Phobos for that?
>>
>> Thank you
>
> Here you go:
>
> import std;
>
> // extract the types that make up the tuple
> auto transposeTuple(T : Tuple!Types[], Types...)(T tuples)
> {
>     // templated function that extracts the ith field of an array of tuples as an array
>     auto extractArray(int i)()
>     {
>         return tuples.map!(a => a[i]).array;
>     }
>     // return tuple of calls to extractArray, one for each tuple index
>     return tuple(staticMap!(extractArray, aliasSeqOf!(Types.length.iota)));
> }
>
> void main() {
>     Tuple!(int, double)[] array;
>     array ~= tuple(1, 2.0);
>     array ~= tuple(3, 4.0);
>     Tuple!(int[], double[]) tuple = array.transposeTuple;
>     assert(tuple[0] == [1, 3]);
>     assert(tuple[1] == [2.0, 4.0]);
> }

^^ Do what he said - I misread the title. :)

--
  Simen
February 17, 2020
On Monday, 17 February 2020 at 11:51:52 UTC, FeepingCreature wrote:
> Here you go:
>
> import std;
>
> // extract the types that make up the tuple
> auto transposeTuple(T : Tuple!Types[], Types...)(T tuples)
> {
>     // templated function that extracts the ith field of an array of tuples as an array
>     auto extractArray(int i)()
>     {
>         return tuples.map!(a => a[i]).array;
>     }
>     // return tuple of calls to extractArray, one for each tuple index
>     return tuple(staticMap!(extractArray, aliasSeqOf!(Types.length.iota)));
> }
>
> void main() {
>     Tuple!(int, double)[] array;
>     array ~= tuple(1, 2.0);
>     array ~= tuple(3, 4.0);
>     Tuple!(int[], double[]) tuple = array.transposeTuple;
>     assert(tuple[0] == [1, 3]);
>     assert(tuple[1] == [2.0, 4.0]);
> }

One tiny thing: the above fails for tuples with named fields, like Tuple!(int, "a", string "b"). This code handles that case, and preserves field names:

import std.meta : staticMap, aliasSeqOf;
import std.typecons : Tuple;
import std.range : array, iota;
import std.algorithm : map;

alias ToArray(T) = T[];
alias ToArray(T...) = T;
alias ToArrayTuple(T : Tuple!U, U...) = Tuple!(staticMap!(ToArray, U));

auto transpose(T : Tuple!U, U...)(T[] arr) {
    auto extract(int i)() { return arr.map!(a => a[i]).array; }
    return ToArrayTuple!T(staticMap!(extract, aliasSeqOf!(T.Types.length.iota)));
}

unittest {
    alias T = Tuple!(int, "a", string, "b");
    auto a = [T(1, "a"), T(2, "b")];
    assert(a.transpose.a == [1, 2]);
    assert(a.transpose.b == ["a", "b"]);
}

--
  Simen
February 17, 2020
On Monday, 17 February 2020 at 12:11:38 UTC, Simen Kjærås wrote:
> On Monday, 17 February 2020 at 11:51:52 UTC, FeepingCreature wrote:
>> [...]
>
> One tiny thing: the above fails for tuples with named fields, like Tuple!(int, "a", string "b"). This code handles that case, and preserves field names:
>
> [...]

Thank you all