www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Splitting a sequence using a binary predicate on adjacent elements

reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
I can't find any algorithm/range in Phobos that can be used to 
split (eagerly or lazily) a sequence using a binary predicate on 
adjacent elements as follows

[1,2,3,5,10,11,12,13,20,21,100].splitBy!"a + 1 != b"()

should evaluate to

[[1,2,3], [5], [10,11,12,13], [20,21], [100]]

.

Is there one?
Oct 17
next sibling parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 17 October 2017 at 13:09:18 UTC, Nordlöw wrote:
 Is there one?
If not, what should we call it?...yet another overload of `splitter()` with a binary predicate and only a single parameter `Range input`?
Oct 17
parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 17 October 2017 at 13:25:01 UTC, Nordlöw wrote:
 On Tuesday, 17 October 2017 at 13:09:18 UTC, Nordlöw wrote:
 Is there one?
If not, what should we call it?...yet another overload of `splitter()` with a binary predicate and only a single parameter `Range input`?
Would probably need to use findAdjacent to get it to work https://dlang.org/phobos/std_algorithm_searching.html#findAdjacent So splitterAdjacent?
Oct 17
prev sibling parent reply Andrea Fontana <nospam example.com> writes:
On Tuesday, 17 October 2017 at 13:09:18 UTC, Nordlöw wrote:
 I can't find any algorithm/range in Phobos that can be used to 
 split (eagerly or lazily) a sequence using a binary predicate 
 on adjacent elements as follows

 [1,2,3,5,10,11,12,13,20,21,100].splitBy!"a + 1 != b"()

 should evaluate to

 [[1,2,3], [5], [10,11,12,13], [20,21], [100]]

 .

 Is there one?
Try this: import std.range; import std.algorithm; import std.stdio; import std.typecons; auto splitBy(alias F, R)(R range) { auto tmp = range .map!(x => tuple(x, 0)) .cumulativeFold!((a,b) => tuple(b[0], (!F(a[0],b[0]))?a[1]:a[1]+1)) .chunkBy!((a,b) => a[1] == b[1]) .map!(x => x.map!(y => y[0])); return tmp; } void main() { [1,2,3,5,10,11,12,13,20,21,100].splitBy!((a,b) => a+1 != b)().writeln; } Andrea
Oct 17
next sibling parent reply Andrea Fontana <nospam example.com> writes:
More phobos-ized version:

https://run.dlang.io/is/iwgeAl

Andrea
Oct 17
parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 17 October 2017 at 15:47:25 UTC, Andrea Fontana wrote:
 More phobos-ized version:

 https://run.dlang.io/is/iwgeAl
Thanks!
Oct 17
prev sibling parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 17 October 2017 at 14:15:02 UTC, Andrea Fontana wrote:
 auto splitBy(alias F, R)(R range)
Because of lazyness shouldn't it be named something with splitter, say splitterBy, instead?
Oct 17
parent reply Andrea Fontana <nospam example.com> writes:
On Wednesday, 18 October 2017 at 06:45:37 UTC, Nordlöw wrote:
 On Tuesday, 17 October 2017 at 14:15:02 UTC, Andrea Fontana 
 wrote:
 auto splitBy(alias F, R)(R range)
Because of lazyness shouldn't it be named something with splitter, say splitterBy, instead?
Yes but I think it is something more similar to chunkBy, but chunkBy says that "predicate must be an equivalence relation, that is, it must be reflexive (pred(x,x) is always true), symmetric (pred(x,y) == pred(y,x)), and transitive (pred(x,y) && pred(y,z) implies pred(x,z)). If this is not the case, the range returned by chunkBy may assert at runtime or behave erratically." If you try to use your data with chunkBy!"a != b+1", it does not work, as expected. I think that my implementation could superseed the current one, since it seems to work in a more generic way. Andrea
Oct 18
parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Wednesday, 18 October 2017 at 07:01:19 UTC, Andrea Fontana 
wrote:
 If you try to use your data with chunkBy!"a != b+1", it does 
 not work, as expected.
What's the motivation behind this limitation? Without it chunkBy!"a + 1 == b" is exactly what I want.
Oct 18
parent Andrea Fontana <nospam example.com> writes:
On Wednesday, 18 October 2017 at 07:26:20 UTC, Nordlöw wrote:
 On Wednesday, 18 October 2017 at 07:01:19 UTC, Andrea Fontana 
 wrote:
 If you try to use your data with chunkBy!"a != b+1", it does 
 not work, as expected.
What's the motivation behind this limitation? Without it chunkBy!"a + 1 == b" is exactly what I want.
Probably it's an implementation problem. On source code you read: // Issue 13595 version(none) // This requires support for non-equivalence relations system unittest { import std.algorithm.comparison : equal; auto r = [1, 2, 3, 4, 5, 6, 7, 8, 9].chunkBy!((x, y) => ((x*y) % 3) == 0); assert(r.equal!equal([ [1], [2, 3, 4], [5, 6, 7], [8, 9] ])); } And other.
Oct 18