I have a list of elements, N, that I want to run through repeatedly until it has M elements, where M can be any integer, not necessarily an integer multiple of N.
I found two ways to do this but neither seems as direct as I would expect is possible. Is there a more native way to do this in Python?
Here is what I came up with. Note that the first method was faster in limited testing.
from math import ceil
def repeat_list_1(values, n):
repeated = values * ceil(n / len(values))
return repeated[:n]
from itertools import cycle
def repeat_list_2(values, n):
values_cycler = cycle(values)
repeated = [next(values_cycler) for _ in range(n)]
return repeated
values = list(range(5))
n = 12
repeated1 = repeat_list_1(values, n)
repeated2 = repeat_list_2(values, n)
assert repeated1 == repeated2
print(repeated1)
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2]
As already stated, there are multiple ways to achieve that, you have to pick your favorite one based on some criteria (speed, code simplicity, ...).
Here's one that I find simple (although it's old style - it doesn't use generators):
>>> def repeat_list_4(values, n): ... d, m = divmod(n, len(values))... return values * d + values[:m]... >>> >>> repeat_list_4(list(range(5)), 12) [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1] >>> repeat_list_4(list(range(5)), 5) [0, 1, 2, 3, 4] >>> repeat_list_4(list(range(5)), 1) [0] >>> repeat_list_4(list(range(5)), 0) []
As a side note, in your example there's n = 12
, but the resulting list has 13 elements.
You can use islice
to get the first n
values of an iterable (called take
in some other languages):
from itertools import cycle, islice
def repeat_list_3(values, n):
return list(islice(cycle(values), n))
I don't know whether this is efficient or not but you can do this.
l = [0, 1, 2, 3, 4]
N = 12
k = (l * (N // len(l) + len(l) - N % len(l)))[:N]
print(k)
# [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1]
First you extend the list upto N + k
number of terms where N + k
is the factor of len(l)
. Finally you slice the resulting list to get N
elements.
numpy has a handy function:
np.resize(values, n)
but you would need to convert it back from np.ndarray
to list
I've done this a couple of times using zip() to define a limit while iterating cyclically through a list.
An example that uses itertools:
from itertools import cycle
values = ['a', 'b', 'c', 1]
n = 10
pool = cycle(values)
for item, limit in zip(pool, range(n)):
print(item)
A way to do this without importing is to iterate cyclically without using itertools, which can be done easily using a generator.
values = ['a', 'b', 'c', 1]
def circular():
while True:
for connection in values:
yield connection
n = 10
for item, limit in zip(circular(), range(n)):
print(item)
I do think however that this solution is clunky and doesn't use zip() as it is intended to be used.
I also took the code from your second example and replaced cycle with a generator to avoid having to import anything.
values = ['a', 'b', 'c', 1]
n = 10
def circular():
while True:
for connection in values:
yield connection
def repeat_list_2(values, n):
values_cycler = circular()
repeated = [next(values_cycler) for _ in range(n)]
return repeated
print(repeat_list_2(values, n))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.