Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
August 09, 2015 Specify variable type for range of associative arrays. | ||||
---|---|---|---|---|
| ||||
I'm just learning D. Something I often do in C# is have an IEnumerable (Range) of some type that is then conditionally filtered. It looks like this: IEnumerable<Dictionary<string, string>> foo = bar; if (baz) { foo = foo.Where(d => d["key"] == value); } I'm trying to do the same in D. Here's what I want to do: Range!(string[string]) records = csvReader!(string[string])(input, null); if (where != "") { records = filter!(r => r[where] == val)(records); } But Range!(string[string]) isn't right, even though that's what the csvReader and filter statements produce. How do I declare that type? I do have a working example, but it's way too verbose (and not following D's indentation/bracket style... sorry about that!): auto gen = new Generator!(string[string])({ auto records = csvReader!(string[string])(input, null); foreach (record; records) { yield(record); } }); if (where != "") { auto prevGen = gen; gen = new Generator!(string[string])({ auto records = filter!(r => r[where] == val)(prevGen); foreach (record; records) { yield(record); } }); } Thanks in advance! |
August 09, 2015 Re: Specify variable type for range of associative arrays. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Davies | On Sunday, 9 August 2015 at 01:29:16 UTC, Christopher Davies wrote: > I'm just learning D. Something I often do in C# is have an IEnumerable (Range) of some type that is then conditionally filtered. It looks like this: > > IEnumerable<Dictionary<string, string>> foo = bar; > > if (baz) > { > foo = foo.Where(d => d["key"] == value); > } > > I'm trying to do the same in D. Here's what I want to do: > > Range!(string[string]) records = csvReader!(string[string])(input, null); > > if (where != "") > { > records = filter!(r => r[where] == val)(records); > } using UFCS (universal function call syntax) you would normally write that as: records =records.filter!(r => r[where] == val)(); and then leveraging D's optional parentheses as: records =records.filter!(r => r[where] == val) This allows you to chain them along with map, filter, reduce etc. with ease e.g. auto result = someRange.filter!(e =>e.isFooCompatible).map!(e => foo(e)).map!(e => e.toBar).array; do you care about the type of result? Not really. It's a range. meaning you can pass iterate over it, pass it to other algorithms. > > But Range!(string[string]) isn't right, even though that's what the csvReader and filter statements produce. How do I declare that type? > Type inference is your friend. auto foo = bar; will work for any type that does not disallow copying (@disable this(this); ) To answer your question what you probably want is not auto records = csvReader!(string[string])(input, null); if (where != "") { records = records.filter!(r => r[where] == val); } but: auto records = csvReader!(string[string])(input, null); if (where != "") { auto filteredRecords = records.filter!(r => r[where] == val); //do something with filteredRecords ... } or just if (where != "") { // if you need the result exclude comment below // or if your operation is for side effects only // leave it. /*auto result =*/ csvReader!(string[string])(input, null) .filter(e => somePred(e)) .continueChainingRanges(withSomeArgs) .untilYoureDone; } If you just want a copy of the filtered results if (where != "") { auto result = csvReader!(string[string])(input, null) .filter(e => e[where] == val).array; // .array causes a separate copy of the values of the result of csvReader } Nic |
August 09, 2015 Re: Specify variable type for range of associative arrays. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nicholas Wilson | On Sunday, 9 August 2015 at 12:54:39 UTC, Nicholas Wilson wrote:
> On Sunday, 9 August 2015 at 01:29:16 UTC, Christopher Davies wrote:
>> [...]
> using UFCS (universal function call syntax) you would normally write that as:
> records =records.filter!(r => r[where] == val)();
> and then leveraging D's optional parentheses as:
> records =records.filter!(r => r[where] == val)
> This allows you to chain them along with map, filter, reduce etc. with ease
> e.g.
> auto result = someRange.filter!(e =>e.isFooCompatible).map!(e => foo(e)).map!(e => e.toBar).array;
>
> do you care about the type of result? Not really. It's a range. meaning you can pass iterate over it, pass it to other algorithms.
>
>>[...]
> Type inference is your friend.
> auto foo = bar;
> will work for any type that does not disallow copying (@disable this(this); )
>
> To answer your question what you probably want is not
> auto records = csvReader!(string[string])(input, null);
>
> if (where != "")
> {
> records = records.filter!(r => r[where] == val);
> }
> but:
> auto records = csvReader!(string[string])(input, null);
>
> if (where != "")
> {
> auto filteredRecords = records.filter!(r => r[where] == val);
> //do something with filteredRecords ...
> }
> or just
> if (where != "")
> {
> // if you need the result exclude comment below
> // or if your operation is for side effects only
> // leave it.
> /*auto result =*/ csvReader!(string[string])(input, null)
> .filter(e => somePred(e))
> .continueChainingRanges(withSomeArgs)
> .untilYoureDone;
>
> }
>
> If you just want a copy of the filtered results
>
> if (where != "")
> {
>
> auto result = csvReader!(string[string])(input, null)
> .filter(e => e[where] == val).array;
> // .array causes a separate copy of the values of the result of csvReader
>
> }
>
> Nic
Thanks so much for the reply. Good to know about UFCS.
The problem is, based on user input, I am optionally filtering a list, possibly passing it through 0, 1, 2 or more filters based on their input. Each successive filter runs on either the original range or the result of the previous filter, if there was one. Then I want to run a ussr-specified computation on the final range... So it would be very nice to be able to reassign the variable after each filter. Is there no good way to do that other than with Generator?
|
August 09, 2015 Re: Specify variable type for range of associative arrays. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Davies | On Sunday, 9 August 2015 at 14:23:33 UTC, Chris Davies wrote: > The problem is, based on user input, I am optionally filtering a list, possibly passing it through 0, 1, 2 or more filters based on their input. Each successive filter runs on either the original range or the result of the previous filter, if there was one. Then I want to run a ussr-specified computation on the final range... So it would be very nice to be able to reassign the variable after each filter. Is there no good way to do that other than with Generator? You can use InputRange: http://dlang.org/phobos/std_range_interfaces.html#InputRange e.g. auto input = yourOriginalData.map!someTransformation; InputRange!string range; if(where != "") range = inputRangeObject(input.filter!(s => s == where)); else range = inputRange(input); |
August 09, 2015 Re: Specify variable type for range of associative arrays. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Sunday, 9 August 2015 at 14:35:23 UTC, Marc Schütz wrote:
> You can use InputRange:
> http://dlang.org/phobos/std_range_interfaces.html#InputRange
>
> e.g.
>
> auto input = yourOriginalData.map!someTransformation;
> InputRange!string range;
> if(where != "")
> range = inputRangeObject(input.filter!(s => s == where));
> else
> range = inputRange(input);
This is exactly it. Thank you!
|
Copyright © 1999-2021 by the D Language Foundation