www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Another cool mini-project: advance a range within n steps from its

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Like "tail" in Unix. Given a range R r and a number size_t n, return a 
TakeExactly!R that's r at no more than n steps from its end:

TakeExactly!R advanceWithin(R)(R r, size_t n)
if (isForwardRange!R);

Invariant:

assert(r.advanceWithin(n).length <= n);

Implementation would send a scout range ahead, etc.

I didn't file an issue for it, but it's a great function to have.


Takers?

Andrei
Dec 04 2015
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-12-04 17:37, Andrei Alexandrescu wrote:
 Like "tail" in Unix. Given a range R r and a number size_t n, return a
 TakeExactly!R that's r at no more than n steps from its end:

 TakeExactly!R advanceWithin(R)(R r, size_t n)
 if (isForwardRange!R);

 Invariant:

 assert(r.advanceWithin(n).length <= n);

 Implementation would send a scout range ahead, etc.

 I didn't file an issue for it, but it's a great function to have.
retro + take? -- /Jacob Carlborg
Dec 04 2015
next sibling parent reply wobbles <grogan.colin gmail.com> writes:
On Friday, 4 December 2015 at 20:01:10 UTC, Jacob Carlborg wrote:
 On 2015-12-04 17:37, Andrei Alexandrescu wrote:
 Like "tail" in Unix. Given a range R r and a number size_t n, 
 return a
 TakeExactly!R that's r at no more than n steps from its end:

 TakeExactly!R advanceWithin(R)(R r, size_t n)
 if (isForwardRange!R);

 Invariant:

 assert(r.advanceWithin(n).length <= n);

 Implementation would send a scout range ahead, etc.

 I didn't file an issue for it, but it's a great function to 
 have.
retro + take?
+ retro to turn it back the normal way? Also, I think this'd work? return r.takeExactly(r.walkLength - n); It wouldn't be particularly efficient though I wouldn't think - as you'd need to walk the whole range to find it's length. r.retro.take(n).retro seems like the easiest fit.
Dec 04 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/04/2015 04:26 PM, wobbles wrote:
 r.retro.take(n).retro seems like the easiest fit.
Doesn't work. Try it! The right solution is to send a scout range ahead. Once the scout got n steps ahead the initial range, advance both until the scout reaches the end. Then return the initial range. It's a nontrivial algorithm that can't be composed easily from existing ones. Andrei
Dec 04 2015
parent reply Sebastiaan Koppe <mail skoppe.eu> writes:
On Friday, 4 December 2015 at 22:53:01 UTC, Andrei Alexandrescu 
wrote:
 Doesn't work. Try it!
void main() { import std.range : retro, take; import std.stdio : writeln; assert([1,2,3,4,5].retro.take(3).retro == [3,4,5]); } What exactly doesn't work?
Dec 04 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/04/2015 06:09 PM, Sebastiaan Koppe wrote:
 On Friday, 4 December 2015 at 22:53:01 UTC, Andrei Alexandrescu wrote:
 Doesn't work. Try it!
void main() { import std.range : retro, take; import std.stdio : writeln; assert([1,2,3,4,5].retro.take(3).retro == [3,4,5]); } What exactly doesn't work?
Forward ranges.
Dec 04 2015
parent reply Sebastiaan Koppe <mail skoppe.eu> writes:
On Saturday, 5 December 2015 at 01:03:05 UTC, Andrei Alexandrescu 
wrote:
 What exactly doesn't work?
Forward ranges.
I see; retro requires a bidirectional range. I was thinking about void main() { import std.algorithm : count; import std.range : drop; import std.stdio : writeln; auto a = [1,2,3,4,5]; writeln(a.drop(a.count-3)); } But it has the downside that it calls front/empty/pop 2*n times. What about using a rangified circular buffer of the same size you want the tail to be, and lazily fill it?
Dec 05 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/05/2015 11:22 AM, Sebastiaan Koppe wrote:
 What about using a rangified circular buffer of the same size you want
 the tail to be, and lazily fill it?
That's O(n) space :o). -- Andrei
Dec 05 2015
parent Sebastiaan Koppe <mail skoppe.eu> writes:
On Saturday, 5 December 2015 at 20:52:23 UTC, Andrei Alexandrescu 
wrote:
 On 12/05/2015 11:22 AM, Sebastiaan Koppe wrote:
 What about using a rangified circular buffer of the same size 
 you want
 the tail to be, and lazily fill it?
That's O(n) space :o). -- Andrei
I know, but it makes half the range primitive calls. Ain't that worth something? Well, it depends I suppose.
Dec 05 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/04/2015 03:01 PM, Jacob Carlborg wrote:
 On 2015-12-04 17:37, Andrei Alexandrescu wrote:
 Like "tail" in Unix. Given a range R r and a number size_t n, return a
 TakeExactly!R that's r at no more than n steps from its end:

 TakeExactly!R advanceWithin(R)(R r, size_t n)
 if (isForwardRange!R);

 Invariant:

 assert(r.advanceWithin(n).length <= n);

 Implementation would send a scout range ahead, etc.

 I didn't file an issue for it, but it's a great function to have.
retro + take?
Try it! -- Andrei
Dec 04 2015
parent Jacob Carlborg <doob me.com> writes:
On 2015-12-04 23:33, Andrei Alexandrescu wrote:

 retro + take?
Try it! -- Andrei
One would need another "retro" as well. But I see now that you have replied it doesn't work for forward ranges. -- /Jacob Carlborg
Dec 05 2015
prev sibling parent Jakob Ovrum <jakobovrum gmail.com> writes:
On Friday, 4 December 2015 at 16:37:36 UTC, Andrei Alexandrescu 
wrote:
 Takers?
https://github.com/D-Programming-Language/phobos/pull/3855
Dec 05 2015