www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Filtering a tuple of containers with indices

reply maik klein <maikklein googlemail.com> writes:
The question is also posted on

https://stackoverflow.com/questions/33757981/filtering-a-tuple-of-containers-with-indicies


template tupIndexToRange(alias Tup, Indices...){
   import std.meta;
   static if(Indicies.length == 0){
     alias tupIndexToRange = AliasSeq!();
   }
   else{
     alias tupIndexToRange = AliasSeq!(Tup[ Indices[0] ][], 
tupIndexToRange!(Tup,Indices[1..$]));
   }
}

void main{
   alias Integrals = AliasSeq!(Array!int, Array!float, 
Array!double);
   Integrals integrals;

   alias IntegralRange = tupIndexToRange!(integrals,0,1);
}

void main{
   alias Integrals = AliasSeq!(Array!int, Array!float, 
Array!double);
   Integrals integrals;

   alias IntegralRange = tupIndexToRange!(integrals,0,1);
}

I want to achieve something like this

auto range = zip(tupIndexToRange!(integrals,0,1));

I think the main problem is that Tup[ Indicies[0] ] doesn't work, 
to me it should have expanded to this 
AliasSeq!(itegrals[0][],integrals[1][]);


This is roughly what I want to achieve

   alias Integrals = AliasSeq!(Array!int, Array!float, 
Array!double);
   Integrals integrals;
   integrals[0].insertBack(1);
   integrals[1].insertBack(2);
   integrals[2].insertBack(3);

   auto range = zip(tuple(integrals[0][],integrals[1][]).expand);
   writeln(range);
   foreach(e;range){
     writeln("element: ",e);
   }
But instead of "auto range = 
zip(tuple(integrals[0][],integrals[1][]).expand);" I want it to 
be generic "auto range = zip(tupIndexToRange!(integrals, 
AliasSeq!(0, 1)).expand);"

Maybe I need use mixins?
Nov 17 2015
parent reply anonymous <anonymous example.com> writes:
On 17.11.2015 15:32, maik klein wrote:
 template tupIndexToRange(alias Tup, Indices...){
[snip] I don't quite understand how that code is supposed to work. Maybe there's just some detail missing, but it could also be that your approach can't work.
 This is roughly what I want to achieve

    alias Integrals = AliasSeq!(Array!int, Array!float, Array!double);
    Integrals integrals;
    integrals[0].insertBack(1);
    integrals[1].insertBack(2);
    integrals[2].insertBack(3);

    auto range = zip(tuple(integrals[0][],integrals[1][]).expand);
    writeln(range);
    foreach(e;range){
      writeln("element: ",e);
    }
 But instead of "auto range =
 zip(tuple(integrals[0][],integrals[1][]).expand);" I want it to be
 generic "auto range = zip(tupIndexToRange!(integrals, AliasSeq!(0,
 1)).expand);"
I think the problem can be split up into two independent tasks: 1) Select fields of a tuple by indices (to drop `integrals[3]`). 2) A "map" function for tuples (to apply `[]` to the selected arrays). Here are two quick implementations of those applied to your problem: ---- template selectFromTuple(indices ...) { auto selectFromTuple(Types...)(Types values) { import std.typecons: tuple, Tuple; static if (indices.length == 0) return Tuple!()(); else { enum headIndex = indices[0]; auto tail = .selectFromTuple!(indices[1 .. $])(values); return tuple(values[headIndex], tail.expand); } } } auto mapTuple(alias op, Types ...)(Types values) { import std.meta: staticMap; import std.typecons: tuple; alias ResultType(T) = typeof(op(T.init)); alias ResultTypes = staticMap!(ResultType, Types); ResultTypes results; foreach (i, v; values) results[i] = op(v); return tuple(results); } void main() { import std.container.array; import std.meta: AliasSeq; import std.range: zip; import std.stdio: writeln; alias Integrals = AliasSeq!(Array!int, Array!float, Array!double); Integrals integrals; integrals[0].insertBack(1); integrals[1].insertBack(2); integrals[2].insertBack(3); auto range = integrals .selectFromTuple!(0, 1).expand .mapTuple!(a => a[]).expand .zip; writeln(range); foreach(e;range){ writeln("element: ",e); } } ---- That looks a lot like range based programming, which makes me think that there could be a way to use actual range algorithms from std.algorithm for this. But I don't see how.
Nov 17 2015
parent reply maik klein <maikklein googlemail.com> writes:
On Tuesday, 17 November 2015 at 15:48:10 UTC, anonymous wrote:
 On 17.11.2015 15:32, maik klein wrote:
 [...]
[snip] I don't quite understand how that code is supposed to work. Maybe there's just some detail missing, but it could also be that your approach can't work. [...]
Thanks but I have one question. .selectFromTuple!(0, 1).expand Does this result in a copy? I avoided doing it like this because I was worried that I would copy every array. But I also don't fully understand when D will copy. Also doing foreach(e;range){ e[0] = 10; e[1] = 10.0f; writeln("element: ",e); } foreach(e;range){ writeln("element: ",e); } doesn't mutate the range at all.
Nov 17 2015
parent anonymous <anonymous example.com> writes:
On 17.11.2015 20:46, maik klein wrote:
 .selectFromTuple!(0, 1).expand

 Does this result in a copy? I avoided doing it like this because I was
 worried that I would copy every array. But I also don't fully understand
 when D will copy.
Yes and no. It copies the Array structs, but it does not copy the elements of the arrays. If I remember correctly, std.container.Array uses reference counting, and copying them should be cheap. By the way, do you have a good reason to go with Array!int rather than int[]? They're similar, but the builtin int[] may be easier to handle.
 Also doing

    foreach(e;range){
      e[0] = 10;
      e[1] = 10.0f;
      writeln("element: ",e);
    }
    foreach(e;range){
      writeln("element: ",e);
    }

 doesn't mutate the range at all.
You need to mark the `e` as `ref`: `foreach(ref e; range)`. Otherwise, it's a copy of the element, and any changes to it are forgotten at the end of the iteration. But even with `ref` it doesn't work. Seems to be a bug in or a limitation of `zip`. Works with `lockstep`: ---- auto ranges = integrals .selectFromTuple!(0, 1).expand .mapTuple!(a => a[]).expand; auto range = ranges.zip; import std.range: lockstep; foreach(ref e0, ref e1; lockstep(ranges)){ e0 = 10; e1 = 10.0f; } foreach(e;range){ writeln("element: ",e); } ----
Nov 17 2015