www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [Request] A way to extract all instance of X from a range

reply deadalnix <deadalnix gmail.com> writes:
Right now, I'm repeating the following pattern many times :

range.map!(x => cast(Foo) x).filter!(x => x !is null)

Which is kind of annoying. Could we get something in phobos to do 
this ?
Mar 14 2016
next sibling parent ZombineDev <petar.p.kirov gmail.com> writes:
On Monday, 14 March 2016 at 08:04:18 UTC, deadalnix wrote:
 Right now, I'm repeating the following pattern many times :

 range.map!(x => cast(Foo) x).filter!(x => x !is null)

 Which is kind of annoying. Could we get something in phobos to 
 do this ?
BTW, .NET has an extension method called OfType<T> that does the same thing: https://msdn.microsoft.com/library/bb360913(v=vs.100).aspx which is different from Cast<T>, which throws an exception if an element can't be converted: https://msdn.microsoft.com/library/bb341406(v=vs.100).aspx How do you want to handle this? With two separate methods as in .NET, or with a template parameter? Maybe something like this: /// Returns a range that lazily iterates over /// the elements in `source` and converts each /// of them to type `T`. /// /// If `throwOnConvError` is false, elements /// that can't be converted will be skipped. auto ofType (T, bool throwOnConvError = true, Range) (Range source) if (isInputRange!Range)
Mar 14 2016
prev sibling next sibling parent reply thedeemon <dlang thedeemon.com> writes:
On Monday, 14 March 2016 at 08:04:18 UTC, deadalnix wrote:
 Right now, I'm repeating the following pattern many times :

 range.map!(x => cast(Foo) x).filter!(x => x !is null)
This reminds me of a function in OCaml extended stdlib that I've used quite often and really miss in D: filter_map : ('a -> 'b option) -> 'a list -> 'b list "filter_map f l call (f a0) (f a1).... (f an) where a0..an are the elements of l. It returns the list of elements bi such as f ai = Some bi (when f returns None, the corresponding element of l is discarded)." Or its variant for OCaml's analog of ranges: filter_map : ('a -> 'b option) -> 'a t -> 'b t "filter_map f e returns an enumeration over all elements x such as f y returns Some x, where y is an element of e." It is really convenient and comes handy in many situations. However it requires some common Option/Maybe type that different libraries could use.
Mar 14 2016
parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On 14/03/2016 11:32, thedeemon wrote:
 filter_map : ('a -> 'b option) -> 'a t -> 'b t

 "filter_map f e returns an enumeration over all elements x such as f y
 returns Some x, where y is an element of e."

 It is really convenient and comes handy in many situations. However it
 requires some common Option/Maybe type that different libraries could use.
There is a pull for Option: https://github.com/D-Programming-Language/phobos/pull/3915 We could have: // fun takes r.front and produces an Option of that type auto mapFilter(alias fun, R)(R r); // turn a possibly null value into an Option Option!T nullFilter(T)(T v) if (isNullable!T); auto src = [new Object(), new T(), null]; auto res = mapFilter!(e => nullFilter(cast(T)e)); assert(res.equal([src[1]]));
Mar 21 2016
next sibling parent reply Timothee Cour via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Mon, Mar 21, 2016 at 4:34 AM, Nick Treleaven via Digitalmars-d <
digitalmars-d puremagic.com> wrote:

 On 14/03/2016 11:32, thedeemon wrote:

 filter_map : ('a -> 'b option) -> 'a t -> 'b t

 "filter_map f e returns an enumeration over all elements x such as f y
 returns Some x, where y is an element of e."

 It is really convenient and comes handy in many situations. However it
 requires some common Option/Maybe type that different libraries could use.
There is a pull for Option: https://github.com/D-Programming-Language/phobos/pull/3915 We could have: // fun takes r.front and produces an Option of that type auto mapFilter(alias fun, R)(R r); // turn a possibly null value into an Option Option!T nullFilter(T)(T v) if (isNullable!T); auto src = [new Object(), new T(), null]; auto res = mapFilter!(e => nullFilter(cast(T)e)); assert(res.equal([src[1]]));
see my proposal [+implementation] for emit http://forum.dlang.org/post/mailman.538.1458560190.26339.digitalmars-d puremagic.com emit is more powerfull, and generalizes map,filter,joiner auto res = src.mapFilter!(e=>nullFilter(cast(T)e)); with emit: auto res = src.emit!((put,e){if(cast(T)e) put(e);});
Mar 21 2016
parent reply Matthias Bentrup <matthias.bentrup googlemail.com> writes:
On Monday, 21 March 2016 at 11:50:06 UTC, Timothee Cour wrote:
 On Mon, Mar 21, 2016 at 4:34 AM, Nick Treleaven via 
 Digitalmars-d < digitalmars-d puremagic.com> wrote:

 On 14/03/2016 11:32, thedeemon wrote:

 filter_map : ('a -> 'b option) -> 'a t -> 'b t

 "filter_map f e returns an enumeration over all elements x 
 such as f y returns Some x, where y is an element of e."

 It is really convenient and comes handy in many situations. 
 However it requires some common Option/Maybe type that 
 different libraries could use.
There is a pull for Option: https://github.com/D-Programming-Language/phobos/pull/3915 We could have: // fun takes r.front and produces an Option of that type auto mapFilter(alias fun, R)(R r); // turn a possibly null value into an Option Option!T nullFilter(T)(T v) if (isNullable!T); auto src = [new Object(), new T(), null]; auto res = mapFilter!(e => nullFilter(cast(T)e)); assert(res.equal([src[1]]));
see my proposal [+implementation] for emit http://forum.dlang.org/post/mailman.538.1458560190.26339.digitalmars-d puremagic.com emit is more powerfull, and generalizes map,filter,joiner auto res = src.mapFilter!(e=>nullFilter(cast(T)e)); with emit: auto res = src.emit!((put,e){if(cast(T)e) put(e);});
Why don't you go for the well-established monadic bind function ? A rangified bind would take a range of inputs, a lambda returning a range of results for one input and return a range of all results. It is logically just a combination of map and concat (which turns a range of ranges into a combined range, but I think that one is missing in the std lib too).
Mar 22 2016
parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On Tuesday, 22 March 2016 at 20:09:51 UTC, Matthias Bentrup wrote:
 It is logically just a combination of map and concat (which 
 turns a range of ranges into a combined range, but I think that 
 one is missing in the std lib too).
http://dlang.org/phobos/std_range.html#.chain
Mar 23 2016
parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Wednesday, 23 March 2016 at 11:36:39 UTC, Nick Treleaven wrote:
 On Tuesday, 22 March 2016 at 20:09:51 UTC, Matthias Bentrup 
 wrote:
 It is logically just a combination of map and concat (which 
 turns a range of ranges into a combined range, but I think 
 that one is missing in the std lib too).
http://dlang.org/phobos/std_range.html#.chain
Or joiner(), if you have a range of ranges: http://dlang.org/phobos/std_algorithm_iteration.html#.joiner
Mar 23 2016
prev sibling parent Jakob Ovrum <jakobovrum gmail.com> writes:
On Monday, 21 March 2016 at 11:34:15 UTC, Nick Treleaven wrote:
 There is a pull for Option:
 https://github.com/D-Programming-Language/phobos/pull/3915

 We could have:

 // fun takes r.front and produces an Option of that type
 auto mapFilter(alias fun, R)(R r);

 // turn a possibly null value into an Option
 Option!T nullFilter(T)(T v) if (isNullable!T);

 auto src = [new Object(), new T(), null];
 auto res = mapFilter!(e => nullFilter(cast(T)e));
 assert(res.equal([src[1]]));
Using the interface proposed in the PR: auto src = [new Object(), new T(), null]; assert(src.map!(e => option(cast(T)e)).joiner.equal(only(src[1])));
Apr 01 2016
prev sibling next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 14 March 2016 at 08:04:18 UTC, deadalnix wrote:
 Right now, I'm repeating the following pattern many times :

 range.map!(x => cast(Foo) x).filter!(x => x !is null)

 Which is kind of annoying. Could we get something in phobos to 
 do this ?
you could use an alias. alias NullFliter = filter!(x => x !is null);
Mar 14 2016
prev sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 14 March 2016 at 08:04:18 UTC, deadalnix wrote:
 Right now, I'm repeating the following pattern many times :

 range.map!(x => cast(Foo) x).filter!(x => x !is null)

 Which is kind of annoying. Could we get something in phobos to 
 do this ?
There you go ;) alias castRange(T) = map!(x => cast(T) x).filter!(x => x !is null);
Mar 14 2016
next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 14 March 2016 at 23:34:37 UTC, Stefan Koch wrote:
 On Monday, 14 March 2016 at 08:04:18 UTC, deadalnix wrote:
 Right now, I'm repeating the following pattern many times :

 range.map!(x => cast(Foo) x).filter!(x => x !is null)

 Which is kind of annoying. Could we get something in phobos to 
 do this ?
There you go ;) alias castRange(T) = map!(x => cast(T) x).filter!(x => x !is null);
Ooops ;) didn't work then it'll has to be done with a wrapper struct ...
Mar 14 2016
prev sibling parent reply Meta <jared771 gmail.com> writes:
On Monday, 14 March 2016 at 23:34:37 UTC, Stefan Koch wrote:
 On Monday, 14 March 2016 at 08:04:18 UTC, deadalnix wrote:
 Right now, I'm repeating the following pattern many times :

 range.map!(x => cast(Foo) x).filter!(x => x !is null)

 Which is kind of annoying. Could we get something in phobos to 
 do this ?
There you go ;) alias castRange(T) = map!(x => cast(T) x).filter!(x => x !is null);
I believe this should work with the latest DMD: alias castRange(T) = t => t.map!(x => cast(T) x).filter!(x => x !is null);
Mar 14 2016
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Tuesday, 15 March 2016 at 04:05:11 UTC, Meta wrote:
 I believe this should work with the latest DMD:

 alias castRange(T) = t => t.map!(x => cast(T) x).filter!(x => x 
 !is null);
No it does not. However this works : auto typeFilter(T, Range)(Range range) { import std.algorithm : filter, map; import std.traits : ForeachType; static assert(is(T == class) && is(T : ForeachType!Range), "typeFilter only works with classes that are derived form each other"); return range.map!(x => cast(T) x).filter!(x => x !is null); } You're Welcome.
Mar 15 2016
parent Meta <jared771 gmail.com> writes:
On Tuesday, 15 March 2016 at 07:42:58 UTC, Stefan Koch wrote:
 On Tuesday, 15 March 2016 at 04:05:11 UTC, Meta wrote:
 I believe this should work with the latest DMD:

 alias castRange(T) = t => t.map!(x => cast(T) x).filter!(x => 
 x !is null);
No it does not. However this works : auto typeFilter(T, Range)(Range range) { import std.algorithm : filter, map; import std.traits : ForeachType; static assert(is(T == class) && is(T : ForeachType!Range), "typeFilter only works with classes that are derived form each other"); return range.map!(x => cast(T) x).filter!(x => x !is null); } You're Welcome.
What version of DMD are you using? It compiles and a small test works for me on 2.070.2.
Mar 15 2016