Thread overview | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 30, 2013 Consume an entire range | ||||
---|---|---|---|---|
| ||||
Is there a simple way to consume a range apart from std.array.array? I don't need to result of the range stored in an array, I just need a lazy map to evaluate completely. |
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brad Anderson | On Thursday, 30 May 2013 at 03:50:52 UTC, Brad Anderson wrote:
> Is there a simple way to consume a range apart from std.array.array? I don't need to result of the range stored in an array, I just need a lazy map to evaluate completely.
Obviously I could just popFront. To be more clear, I want something like eat() or consume() or exhaust() that I can tack on the end of my chained algorithm calls.
|
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brad Anderson | On Thursday, May 30, 2013 05:53:02 Brad Anderson wrote:
> On Thursday, 30 May 2013 at 03:50:52 UTC, Brad Anderson wrote:
> > Is there a simple way to consume a range apart from std.array.array? I don't need to result of the range stored in an array, I just need a lazy map to evaluate completely.
>
> Obviously I could just popFront. To be more clear, I want
> something like eat() or consume() or exhaust() that I can tack on
> the end of my chained algorithm calls.
If you specifically want to iterate over it, then I think that you need to repeatedly call popFront (or callPopFrontN if it hasLength). However, if what you want is for the resultant range to be empty, you can use std.range.takeNone. If it can, it'll return the same range type as the original, and if it can't, it'll return takeExactly(range, 0).
- Jonathan M Davis
|
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brad Anderson | On Thursday, 30 May 2013 at 03:53:06 UTC, Brad Anderson wrote:
> On Thursday, 30 May 2013 at 03:50:52 UTC, Brad Anderson wrote:
>> Is there a simple way to consume a range apart from std.array.array? I don't need to result of the range stored in an array, I just need a lazy map to evaluate completely.
>
> Obviously I could just popFront. To be more clear, I want something like eat() or consume() or exhaust() that I can tack on the end of my chained algorithm calls.
There's "walkLength"?
|
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Diggory | On Thursday, May 30, 2013 06:12:51 Diggory wrote:
> On Thursday, 30 May 2013 at 03:53:06 UTC, Brad Anderson wrote:
> > On Thursday, 30 May 2013 at 03:50:52 UTC, Brad Anderson wrote:
> >> Is there a simple way to consume a range apart from std.array.array? I don't need to result of the range stored in an array, I just need a lazy map to evaluate completely.
> >
> > Obviously I could just popFront. To be more clear, I want
> > something like eat() or consume() or exhaust() that I can tack
> > on the end of my chained algorithm calls.
>
> There's "walkLength"?
Ah, I should have thought of that, though that won't work if the range defines length. Of course, if it defines length, you can always use popFrontN with length.
- Jonathan M Davis
|
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Thursday, 30 May 2013 at 04:18:14 UTC, Jonathan M Davis wrote:
> On Thursday, May 30, 2013 06:12:51 Diggory wrote:
>> On Thursday, 30 May 2013 at 03:53:06 UTC, Brad Anderson wrote:
>> > On Thursday, 30 May 2013 at 03:50:52 UTC, Brad Anderson wrote:
>> >> Is there a simple way to consume a range apart from
>> >> std.array.array? I don't need to result of the range stored
>> >> in an array, I just need a lazy map to evaluate completely.
>> >
>> > Obviously I could just popFront. To be more clear, I want
>> > something like eat() or consume() or exhaust() that I can tack
>> > on the end of my chained algorithm calls.
>>
>> There's "walkLength"?
>
> Ah, I should have thought of that, though that won't work if the range defines
> length. Of course, if it defines length, you can always use popFrontN with
> length.
>
> - Jonathan M Davis
Do you think it would be worth adding a "consume" method to std.range or std.algorithm?
|
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Thursday, 30 May 2013 at 04:00:39 UTC, Jonathan M Davis wrote: > On Thursday, May 30, 2013 05:53:02 Brad Anderson wrote: >> On Thursday, 30 May 2013 at 03:50:52 UTC, Brad Anderson wrote: >> > Is there a simple way to consume a range apart from >> > std.array.array? I don't need to result of the range stored in >> > an array, I just need a lazy map to evaluate completely. >> >> Obviously I could just popFront. To be more clear, I want >> something like eat() or consume() or exhaust() that I can tack on >> the end of my chained algorithm calls. > > If you specifically want to iterate over it, then I think that you need to > repeatedly call popFront (or callPopFrontN if it hasLength). However, if what > you want is for the resultant range to be empty, you can use > std.range.takeNone. If it can, it'll return the same range type as the > original, and if it can't, it'll return takeExactly(range, 0). > > - Jonathan M Davis There was a filter in the change so I had no length. The tailing map had a void element type which mean foreach didn't work on it. I ended up with: void eat(R)(R r) { while(!r.empty) { r.front; r.popFront(); } } I was actually just playing around reimplementing Andrei's example from his InformIT article[1] using std.algorithm and friends. It went from: import std.stdio, std.string; void main() { uint[string] dic; foreach (line; stdin.byLine) { // Break sentence into words string[] words = split(strip(line)); // Add each word in the sentence to the vocabulary foreach (word; words) { if (word in dic) continue; // nothing to do uint newID = dic.length; dic[word] = newID; writeln(newID, '\t', word); } } } to: import std.stdio, std.algorithm, std.array; void eat(R)(R r) { while(!r.empty) { r.front; r.popFront; } } void main() { size_t[dstring] dic; stdin.byLine .joiner(" ") .array .splitter(' ') .filter!(w => !w.empty && w !in dic) .map!(w => writeln(dic[w.idup] = dic.length, '\t', w)) .eat; } I would have prefered to not use joiner() but working with ranges of ranges of ranges (splitter() on each line) got a bit weird and confusing. splitter() needed array slicing and length which joiner() doesn't have so I had to use array(). I was confused about why I was suddenly getting dchar[] out the other end but found the StackOverflow question [2] in which you explain why joiner does that (you really kick ass at answering StackOverflow questions, Jonathan). Having a variant of splitter that ignores empty tokens would be nice to have too. 1. http://www.informit.com/articles/article.aspx?p=1381876&seqNum=4 2. http://stackoverflow.com/questions/12288465/std-algorithm-joinerstring-string-why-result-elements-are-dchar-and-not-ch |
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Diggory | On Thursday, 30 May 2013 at 04:12:56 UTC, Diggory wrote:
> On Thursday, 30 May 2013 at 03:53:06 UTC, Brad Anderson wrote:
>> On Thursday, 30 May 2013 at 03:50:52 UTC, Brad Anderson wrote:
>>> Is there a simple way to consume a range apart from std.array.array? I don't need to result of the range stored in an array, I just need a lazy map to evaluate completely.
>>
>> Obviously I could just popFront. To be more clear, I want something like eat() or consume() or exhaust() that I can tack on the end of my chained algorithm calls.
>
> There's "walkLength"?
I tried that. There is an isInputRange && !isInfinite template constraint but I don't see how my stuff didn't meet that requirement.
|
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brad Anderson | On Thursday, 30 May 2013 at 04:30:11 UTC, Brad Anderson wrote:
> [snip]
> import std.stdio, std.algorithm, std.array;
>
> void eat(R)(R r) { while(!r.empty) { r.front; r.popFront; } }
>
> void main() {
> size_t[dstring] dic;
> stdin.byLine
> .joiner(" ")
> .array
> .splitter(' ')
> .filter!(w => !w.empty && w !in dic)
> .map!(w => writeln(dic[w.idup] = dic.length, '\t', w))
> .eat;
> }
>
> I would have prefered to not use joiner() but working with ranges of ranges of ranges (splitter() on each line) got a bit weird and confusing.
Ok, I guess it's not that weird after all:
void main() {
size_t[string] dic;
stdin.byLine
.map!(l => l.splitter(' ')
.filter!(w => !w.empty && w !in dic)
.map!(w => writeln(dic[w.idup] = dic.length, '\t', w)).eat).eat;
}
|
May 30, 2013 Re: Consume an entire range | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brad Anderson | Brad Anderson:
> import std.stdio, std.algorithm, std.array;
>
> void eat(R)(R r) { while(!r.empty) { r.front; r.popFront; } }
>
> void main() {
> size_t[dstring] dic;
> stdin.byLine
> .joiner(" ")
> .array
> .splitter(' ')
> .filter!(w => !w.empty && w !in dic)
> .map!(w => writeln(dic[w.idup] = dic.length, '\t', w))
> .eat;
> }
>
> I would have prefered to not use joiner() but working with ranges of ranges of ranges (splitter() on each line) got a bit weird and confusing.
Maybe here it's better to work on lines. Alternatively I don't know if you can read the whole input there.
It's usually better to give only pure functions to filter/map, because in Bugzilla I've shown those higher order functions don't work well otherwise.
So I prefer a terminal function that takes an impure function and returns nothing, something like:
...
.filter!(w => !w.empty && w !in dic)
.forEach!((w) { writeln(dic[w.idup] = dic.length, '\t', w); });
Bye,
bearophile
|
Copyright © 1999-2021 by the D Language Foundation