2

Say you have this:

foo = [1,2,3,4,5,6,7,8,9,10]
bar = 22

I want to get bar many values from foo, repeating from the start after reaching the end. So for these inputs, the results should be 1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2.

I have this working code:

foo = [1,2,3,4,5,6,7,8,9,10]
bar = 22

x = 0

for i in range(bar):
    print(foo[x])

    # increment
    if x == 9:
        x = 0
    # back to 1
    else:
        x += 1

but is there a shorter way, that doesn't use a temporary variable, x?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153

3 Answers3

6

While Kemp's solution does work, I believe a more pythonic solution is to use the itertools package:

import itertools
foo = [1,2,3,4,5,6,7,8,9,10]
bar = 22
for i in itertools.islice(itertools.cycle(foo), bar):
    print(i)

cycle creates an endlessly repeating iterator over the specified iterable. After we consume the 10, the iterator will be back at 1.

islice works like the typical list slicing syntax, but it works on iterators and generators in addition to containers. We can use that to take bar items from the iterator.

This is a bit more flexible because it doesn't require that foo be subscriptable. In other words, this will work even if:

  • foo is an iterator (e.g. foo = iter(foo))
  • foo is a generator (e.g. foo = (x*2 for x in foo))
  • foo is a special proxy object like dict_keys or dict_values (e.g. foo = {x: str(x) for x in foo}.keys())
0x5453
  • 12,753
  • 1
  • 32
  • 61
4

You're probably looking for the modulo operator:

foo = [1,2,3,4,5,6,7,8,9,10]
bar = 22

for i in range(bar):
    print(foo[i % len(foo)])

This will solve your question as posed, but see also 0x5453's answer for a more general solution using itertools.

Kemp
  • 3,467
  • 1
  • 18
  • 27
1

you don't need loops at all:

foo = [1,2,3,4,5,6,7,8,9,10]
bar = 22
big_list = foo * bar #you could do this more memory efficiently by working out how many times you need to join the list based on its length.
print(list[0:bar])

Here's the 'memory efficient' way of doing it, not quite as easy to decipher, you could use some helper variables to split out each part of the calculation. Having additional variables isn't necessarily a bad thing!

foo = [1,2,3,4,5,6,7,8,9,10]
bar = 22
print(foo * (int(bar/len(foo)))+foo[0:(bar%len(foo))])
JeffUK
  • 4,107
  • 2
  • 20
  • 34
  • You definitely should be making a shorter list. In this case you've constructed a list of 220 items, just to print 22 of them. Also, this will print a string representation of the list rather than each item on a new line as per the original example, so the print probably needs tweaking as well. – Kemp Jun 03 '21 at 14:26
  • @kemp That's left as an exercise for the reader. OP's print statement won't give the output they say it will give so it's ambiguous as to what they actually want. – JeffUK Jun 03 '21 at 14:28
  • Fair point. I took it as just being a more compact way to show us than making the question 22 lines longer just for that output. They didn't say there was anything wrong with the code's output as such, so I took that as correct. – Kemp Jun 03 '21 at 14:29