Streaming sample.

    Iterate over seq (once!) keeping k random elements with uniform
    distribution.

    As a special case, if ``k`` is ``None``, then ``list(seq)`` is
    returned.

    :param seq: iterable of things to sample from
    :param k: size of desired sample
    :param limit: stop reading ``seq`` after considering this many
    :return: list of elements from seq, length k (or less if seq is
             short)

def streaming_sample(seq, k, limit=None):
    '''Streaming sample.

    Iterate over seq (once!) keeping k random elements with uniform
    distribution.

    As a special case, if ``k`` is ``None``, then ``list(seq)`` is
    returned.

    :param seq: iterable of things to sample from
    :param k: size of desired sample
    :param limit: stop reading ``seq`` after considering this many
    :return: list of elements from seq, length k (or less if seq is
             short)
    '''
    if k is None:
        return list(seq)

    seq = iter(seq)
    if limit is not None:
        k = min(limit, k)
        limit -= k
    result = list(islice(seq, k))
    for count, x in enumerate(islice(seq, limit), len(result)):
        if rand.random() < (1.0 / count):
            result[rand.randint(0, k-1)] = x
    return result