Most computationally efficient way to build a Python list with repeating and iterating numbers like [0, 0, 0, 1, 1, 1, 2, 2, 2 . . . ,32]

  • A+
Category:Languages

I want to make an array that looks something like

[0, 0, 0, 1, 1 , 1, 2, 2, 2,  . . .etc] 

or

[4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, . . . etc]

There is something like

segments = [i for i in range(32)]   

which will make

 [ 1, 2, 3, 4, 5, . . . etc] 

There are ways where I can call 3 separate sets of i in range(32) but I am looking to save computation by only calling it once.

What's the most computationally efficient and programatically elegant way of making array like

[0, 0, 0, 1, 1 , 1, 2, 2, 2,  . . .etc] 

 


Use itertools.chain on itertools.repeat iterables:

import itertools  result = list(itertools.chain.from_iterable(itertools.repeat(i,3) for i in range(32)))  print(result) 

result:

[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31]

This technique avoids the creation of intermediate lists and minimizes the pure python loops (one python loop total, using map could be possible to remove that last one, but that would require a lambda in that case, which adds one more function call).

EDIT: let's bench this answer and Ted's answer

import itertools,time  n=1000000  start_time = time.time() for _ in range(n):     list(itertools.chain.from_iterable(itertools.repeat(i,3) for i in range(32)))  print("itertools",time.time() - start_time)  start_time = time.time() for _ in range(n):     [i for i in range(32) for _ in range(3)] print("flat listcomp",time.time() - start_time) 

results:

itertools 10.719785928726196 flat listcomp 13.869723081588745 

so using itertools instead of list comprension is around 30% faster (python 3.4, windows)

Notes:

the small number of repeats generates a lot of itertools.repeat calls in the inner loop, so in that case of 3 repeats, it's faster to do what NickA suggests:

list(itertools.chain.from_iterable((i,)*3 for i in range(32))) 

(7 seconds vs 10 in the above bench)

And numpy solution is even faster (around 1.5 second), if you can use numpy:

import numpy as np np.arange(32).repeat(3)  # credits: liliscent  

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: