www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 13865] New: std.range.rangeSplit

https://issues.dlang.org/show_bug.cgi?id=13865

          Issue ID: 13865
           Summary: std.range.rangeSplit
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: Phobos
          Assignee: nobody puremagic.com
          Reporter: bearophile_hugs eml.cc

I suggest to add to Phobos a range similar to the "tee" function of the Python
itertools:

https://docs.python.org/2/library/itertools.html#itertools.tee

http://code.activestate.com/recipes/305588-simple-example-to-show-off-itertoolstee/

http://discontinuously.com/2012/06/inside-python-tee/

- - - - - - - -

The Python description:

itertools.tee(iterable[, n=2])
Return n independent iterators from a single iterable. Equivalent to:


def tee(iterable, n=2):
    it = iter(iterable)
    deques = [collections.deque() for i in range(n)]
    def gen(mydeque):
        while True:
            if not mydeque:             # when the local deque is empty
                newval = next(it)       # fetch a new value and
                for d in deques:        # load it to all the deques
                    d.append(newval)
            yield mydeque.popleft()
    return tuple(gen(d) for d in deques)

- - - - - - - -

A bare-bones implementation in D (this is not meant to be the efficient and
reliable implementation for Phobos):


import std.traits: hasIndirections;
import std.concurrency: Generator, yield;
import std.range: ElementType;
import std.algorithm: map;
import std.array: array;

import queue_usage2: GrowableCircularQueue;

auto rangeDup(R)(R seq, in uint n=2) {
    alias T = ElementType!R;
    auto deques = new GrowableCircularQueue!T[n];

    auto gen(ref GrowableCircularQueue!T mydeque) {
        return new Generator!T({
            while (true) {
                if (mydeque.empty) {
                    auto newVal = seq.front;
                    seq.popFront;
                    foreach (ref d; deques)
                        d.push(newVal);
                }
                yield(mydeque.pop);
            }
        });
    }

    return deques.map!gen.array;
}

// An usage example:

enum sternBrocot = () => new Generator!uint({
    GrowableCircularQueue!uint sb;
    sb.push(1u);
    sb.push(1u);
    while (true) {
        sb.push(sb[0] + sb[1]);
        sb.push(sb[1]);
        yield(sb.pop);
    }
});

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

    auto ss = rangeDup(sternBrocot());
    ss[1].popFront;
    assert(zip(ss[0], ss[1]).take(1_000).all!(t => gcd(t[0], t[1]) == 1));
}

--
Dec 15 2014