digitalmars.D.learn - Filtering a tuple of containers with indices
- maik klein (46/46) Nov 17 2015 The question is also posted on
- anonymous (58/74) Nov 17 2015 [snip]
- maik klein (16/23) Nov 17 2015 Thanks but I have one question.
- anonymous (25/39) Nov 17 2015 Yes and no. It copies the Array structs, but it does not copy the
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
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
On Tuesday, 17 November 2015 at 15:48:10 UTC, anonymous wrote:On 17.11.2015 15:32, maik klein wrote: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.[...][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. [...]
Nov 17 2015
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