Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

islice on nested iterators

I'm trying to reuse the solution at the end of How to automatically generate N "distinct" colors? using Python 2.7.

Unfortunately, the code below never returns, since even though islice() requests the first 100 iterations, it seems that the inner-map calls like

gethsvs = lambda: flatten(itertools.imap(genhsv, getfracs()))

force getting all iterations. Instead of passing the number of iterations to all lambda functions, is there a way to make an islice() call at the main code, as below, but making it get only the first 100 iterations in all inner maps as well?

import colorsys, itertools, numpy as np
from fractions import Fraction

def zenos_dichotomy():
    '''
http://en.wikipedia.org/wiki/1/2_%2B_1/4_%2B_1/8_%2B_1/16_%2B_%C2%B7_%C2%B7_%C2%B7
    '''
    for k in itertools.count():
        yield Fraction(1, 2 ** k)

def getfracs():
    '''
    [Fraction(0, 1), Fraction(1, 2), Fraction(1, 4), Fraction(3, 4), Fraction(1, 8), Fraction(3, 8), Fraction(5, 8), Fraction(7, 8), Fraction(1, 16), Fraction(3, 16), ...]
    [0.0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 0.0625, 0.1875, ...]
    '''
    yield 0
    for k in zenos_dichotomy():
        i = k.denominator # [1,2,4,8,16,...]
        for j in range(1, i, 2):
            yield Fraction(j, i)

'''Can be used for the v in hsv to map linear values 0..1 to something that looks equidistant.'''
bias = lambda x: (np.sqrt(x / 3) / Fraction(2, 3) + Fraction(1, 3)) / Fraction(6, 5)

def genhsv(h):
    for s in [Fraction(6, 10)]: # optionally use range
        for v in [Fraction(8, 10), Fraction(5, 10)]: # could use range too
            yield (h, s, v) # use bias for v here if you use range

genrgb = lambda x: colorsys.hsv_to_rgb(*x)
flatten = itertools.chain.from_iterable
gethsvs = lambda: flatten(itertools.imap(genhsv, getfracs()))
getrgbs = lambda: itertools.imap(genrgb, gethsvs())

def genhtml(x):
    uint8tuple = itertools.imap(lambda y: int(y * 255), x)
    return 'rgb({},{},{})'.format(*uint8tuple)

gethtmlcolors = lambda: map(genhtml, getrgbs())

if __name__ == '__main__':
    print(list(itertools.islice(gethtmlcolors(), 100)))
like image 548
Oren Avatar asked Mar 18 '26 02:03

Oren


1 Answers

You are using map() instead of itertools.imap() in your gethtmlcolors lambda:

gethtmlcolors = lambda: map(genhtml, getrgbs())

In python 2, map() will try and process all elements of the input iterable. Change that to use imap() and everything works:

gethtmlcolors = lambda: itertools.imap(genhtml, getrgbs())
like image 178
Martijn Pieters Avatar answered Mar 19 '26 14:03

Martijn Pieters



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!