Thread overview
Last element of a forward range
Apr 12, 2014
bearophile
Apr 12, 2014
bearophile
Apr 12, 2014
monarch_dodra
April 12, 2014
If I have a range like this, how do you find its last item using Phobos?

A simple way is to use seq.array.back, but this wastes memory. Another simple way is to use a foreach loop keeping the last seen. But do you know if there is a function to do in Phobos? And if such function is not present (walkBack? backWalk?) is it a good idea to add it to Phobos?


void main() {
    import std.stdio, std.algorithm, std.range;

    int m = 75;
    auto seq = recurrence!q{ a[n - 1] + a[n - 2] }(1, 1)
               .until!(x => x > m)(OpenRight.no);

    seq.array.back.writeln; // 89
    //seq.back.writeln;

    auto last = -1;
    foreach (immutable x; seq)
        last = x;
    last.writeln;
}


Bye,
bearophile
April 12, 2014
On Fri, 11 Apr 2014 21:05:26 -0400, bearophile <bearophileHUGS@lycos.com> wrote:

> If I have a range like this, how do you find its last item using Phobos?
>
> A simple way is to use seq.array.back, but this wastes memory. Another simple way is to use a foreach loop keeping the last seen. But do you know if there is a function to do in Phobos? And if such function is not present (walkBack? backWalk?) is it a good idea to add it to Phobos?

Interesting problem. Given that it is a forward range, a zip between it and a saved copy that is advanced by one may work.

-Steve
April 12, 2014
Steven Schveighoffer:

> Interesting problem.

And it's not an academic one, I have already faced it two or three times :-)


> Given that it is a forward range, a zip between it and a saved copy that is advanced by one may work.

This compiles and gives the expected output, but how do you extract the last item with this?

seq.zip(seq.dropOne).writeln;

I have written I've added an ER to Phobos with some preliminary code:
https://issues.dlang.org/show_bug.cgi?id=12564

Bye,
bearophile
April 12, 2014
On Saturday, 12 April 2014 at 10:27:00 UTC, bearophile wrote:
> Steven Schveighoffer:
>
>> Interesting problem.
>
> And it's not an academic one, I have already faced it two or three times :-)
>
>
>> Given that it is a forward range, a zip between it and a saved copy that is advanced by one may work.
>
> This compiles and gives the expected output, but how do you extract the last item with this?
>
> seq.zip(seq.dropOne).writeln;

For starters, you can't in the sense that writeln takes by value, and your zip has value semantics. So in fact, it is still unchanged. BTW: That UFCS "seq.zip(someOtherRange)": Ew.

So you'd need to start with a:
auto z = zip(seq, seq.dropOne);
while (!z.empty)
    z.popFront();

That's step one. Step two would be actually extracting the remainaing range. In theory, you can't. In practice, you can hack around the implementation by:
zip.ranges[1].front;

Turns out "ranges" is not private. I wouldn't use this.

The second, is modifying the stopping policy on the fly:
zip.stoppingPolicy = StoppingPolicy.longest;
auto a = zip.front[1];

I think both are *very* hackish.
I'd do this:

auto bck = seq.save; seq.popFront();
while (!seq.empty)
{
    bck.popFront();
    seq.popFront();
}
auto last = bck.front;