p.brown
p.brown

Reputation: 2553

Make a new list containing every Nth item in the original list

Say we have a list of integers from 0 to 1000:

[0, 1, 2, 3, ..., 997, 998, 999]

How do I get a new list containing the first and every subsequent 10th item?

[0, 10, 20, 30, ..., 990]

I can do this using a for loop, but is there a neater way, perhaps even in one line of code?

Upvotes: 246

Views: 380841

Answers (9)

Ned Deily
Ned Deily

Reputation: 85045

>>> xs = list(range(165))
>>> xs[0::10]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]

Note that this is around 100 times faster than looping and checking a modulus for each element:

$ python -m timeit -s "xs = list(range(1000))" "[x for i, x in enumerate(xs) if i % 10 == 0]"
500 loops, best of 5: 476 usec per loop

$ python -m timeit -s "xs = list(range(1000))" "xs[0::10]"
100000 loops, best of 5: 3.32 usec per loop

Upvotes: 407

tuergeist
tuergeist

Reputation: 9391

Use range(start, end, step)

li = list(range(0, 1000, 10))

[0, 10, 20, 30, 40, 50, 60, 70, 80, 90 ... 990]

Or, if you have a list use slice: From manual: s[i:j:k] slice of s from i to j with step k

yourlist = [0, ... ,10 ...]  
sub = yourlist[::10]  # same as yourlist[0:100:10]

>>> sub
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

Upvotes: 36

Denis Otkidach
Denis Otkidach

Reputation: 33200

  1. source_list[::10] is the most obvious, but this doesn't work for any iterable and is not memory efficient for large lists.
  2. itertools.islice(source_sequence, 0, None, 10) works for any iterable and is memory-efficient, but probably is not the fastest solution for large list and big step.
  3. (source_list[i] for i in xrange(0, len(source_list), 10))

Upvotes: 75

Santi
Santi

Reputation: 4468

List comprehensions are exactly made for that:

smaller_list = [x for x in range(100001) if x % 10 == 0]

You can get more info about them in the python official documentation: http://docs.python.org/tutorial/datastructures.html#list-comprehensions

Upvotes: -10

Nick Dandoulakis
Nick Dandoulakis

Reputation: 43120

You can use the slice operator like this:

l = [1,2,3,4,5]
l2 = l[::2] # get subsequent 2nd item

Upvotes: 33

van
van

Reputation: 76992

Why not just use a step parameter of range function as well to get:

l = range(0, 1000, 10)

For comparison, on my machine:

H:\>python -m timeit -s "l = range(1000)" "l1 = [x for x in l if x % 10 == 0]"
10000 loops, best of 3: 90.8 usec per loop
H:\>python -m timeit -s "l = range(1000)" "l1 = l[0::10]"
1000000 loops, best of 3: 0.861 usec per loop
H:\>python -m timeit -s "l = range(0, 1000, 10)"
100000000 loops, best of 3: 0.0172 usec per loop

Upvotes: 4

PaulMcG
PaulMcG

Reputation: 63729

Here is a better implementation of an "every 10th item" list comprehension, that does not use the list contents as part of the membership test:

>>> l = range(165)
>>> [ item for i,item in enumerate(l) if i%10==0 ]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]
>>> l = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
>>> [ item for i,item in enumerate(l) if i%10==0 ]
['A', 'K', 'U']

But this is still far slower than just using list slicing.

Upvotes: 1

lutz
lutz

Reputation:

existing_list = range(0, 1001)
filtered_list = [i for i in existing_list if i % 10 == 0]

Upvotes: 3

David Z
David Z

Reputation: 131600

newlist = oldlist[::10]

This picks out every 10th element of the list.

Upvotes: 13

Related Questions