Thread overview
Splitting a sequence using a binary predicate on adjacent elements
Oct 17, 2017
Nordlöw
Oct 17, 2017
Nordlöw
Oct 17, 2017
jmh530
Oct 17, 2017
Andrea Fontana
Oct 17, 2017
Andrea Fontana
Oct 18, 2017
Nordlöw
Oct 18, 2017
Nordlöw
Oct 18, 2017
Andrea Fontana
Oct 18, 2017
Nordlöw
Oct 18, 2017
Andrea Fontana
October 17, 2017
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?
October 17, 2017
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`?
October 17, 2017
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?
October 17, 2017
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
October 17, 2017
More phobos-ized version:

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

Andrea


October 18, 2017
On Tuesday, 17 October 2017 at 15:47:25 UTC, Andrea Fontana wrote:
> More phobos-ized version:
>
> https://run.dlang.io/is/iwgeAl

Thanks!
October 18, 2017
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?
October 18, 2017
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
October 18, 2017
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.
October 18, 2017
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.