Consume an entire range

Brad Anderson eco at gnuk.net
Wed May 29 21:30:08 PDT 2013


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


More information about the Digitalmars-d-learn mailing list