Thread overview | ||||||
---|---|---|---|---|---|---|
|
November 17, 2015 Filtering a tuple of containers with indices | ||||
---|---|---|---|---|
| ||||
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? |
November 17, 2015 Re: Filtering a tuple of containers with indices | ||||
---|---|---|---|---|
| ||||
Posted in reply to maik klein | 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. |
November 17, 2015 Re: Filtering a tuple of containers with indices | ||||
---|---|---|---|---|
| ||||
Posted in reply to anonymous | 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.
|
November 17, 2015 Re: Filtering a tuple of containers with indices | ||||
---|---|---|---|---|
| ||||
Posted in reply to maik klein | 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); } ---- |
Copyright © 1999-2021 by the D Language Foundation