bongbang bongbang - 4 months ago 20
Python Question

Unspool frequency table by list comprehension

Here's a frequency table implemented as a list.

table = [1,3,2]


The desired output is a list of individual values.

unspooled = [0, 1, 1, 1, 2, 2]


The following syntax will get the job done.

sum((freq*[score] for score, freq in enumerate(table)), [])


As an exercise to test my understanding, however, I'd like to know if there's a way to accomplish this with pure list comprehension. Thank you.

(Or secondarily, if there's a way to do it that is more expressive than what I have that isn't pure list comprehension, I'm open to that, too.)

PS Apparently, my syntax yields terrible performance.

Update. Timings of all the suggested solutions.

In [9]: table
Out[9]: range(0, 1000)

In [10]: %timeit [i for i, x in enumerate(table) for _ in range(x)]
10 loops, best of 3: 27.1 ms per loop

In [11]: %timeit [ind for ind in range(len(table)) for val in range(table[ind])]
10 loops, best of 3: 27 ms per loop

In [12]: %timeit reduce( lambda x,y:x+y, [ [i]*frq for i,frq in enumerate(table)] )
1 loop, best of 3: 1.11 s per loop

In [13]: %timeit list(itertools.chain(freq*[score] for score, freq in enumerate(table))
100 loops, best of 3: 3.84 ms per loop

Answer

I believe this would work:

unspooled = [ind for ind in range(len(table)) for val in range(table[ind])]