Méthode pythonique pour renvoyer la liste de chaque nième élément dans une liste plus grande


171

Disons que nous avons une liste de nombres de 0 à 1000. Existe-t-il un moyen pythonique / efficace de produire une liste du premier élément et de chaque 10e élément suivant, c'est [0, 10, 20, 30, ... ]-à- dire ?

Oui, je peux le faire en utilisant une boucle for, mais je me demande s'il existe un moyen plus propre de le faire, peut-être même en une seule ligne?

Réponses:


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

Notez que c'est environ 100 fois plus rapide que de boucler et de vérifier un module pour chaque élément:

$ python -m timeit -s "lst = list(range(1000))" "lst1 = [x for x in lst if x % 10 == 0]"
1000 loops, best of 3: 525 usec per loop
$ python -m timeit -s "lst = list(range(1000))" "lst1 = lst[0::10]"
100000 loops, best of 3: 4.02 usec per loop

4
Bien sûr, les compréhensions de listes sont plus puissantes en général. OTOH, la question pose une liste existante et, dans ce cas, une tranche fonctionne très bien.
Ned Deily

J'ai commenté cela ci-dessous dans les réponses de compréhension de la liste. Soyez prudent avec "si x% 10 == 0". Cela ne fonctionne qu'avec cet exemple de liste particulier, mais si la liste d'entrée est par exemple l = range (0,1000,2), elle ne sortira pas tous les 10 éléments.
Andre Miller

12
@Andre: très vrai. Voici donc un exemple d'une modeste fonctionnalité de langage, l'opérateur de tranche, qui s'avère dans ce cas (1) pour faciliter l'obtention des résultats corrects; (2) donne une expression plus concise; et (3) se trouve être 2 ordres de grandeur plus rapide. (1) est de loin la préoccupation la plus importante, bien sûr, mais, grâce à la conception et à la mise en œuvre soignées du langage, vous obtenez les trois pour le prix de 1. Belle question et réponses.
Ned Deily

2
Le 0est redondant dans l[0::10]. l[::10]est plus lisible, moins déroutant.
Konstantin Schubert

Je suis surpris par la comparaison des performances de 0,5 seconde pour la compréhension de la liste et de 0,4 s pour la tranche de liste. Cela semble très lent, pourquoi le découpage de la liste a besoin de 100 000 boucles pour une liste de 1 000!?
Damo le

58
  1. source_list[::10] est le plus évident, mais cela ne fonctionne pour aucun itérable et n'est pas efficace en mémoire pour les grandes listes.
  2. itertools.islice(source_sequence, 0, None, 10) fonctionne pour tout itérable et est efficace en mémoire, mais ce n'est probablement pas la solution la plus rapide pour les grandes listes et les grandes étapes.
  3. (source_list[i] for i in xrange(0, len(source_list), 10))

1
+1 Meilleure réponse, OMI. Les trois propositions sont des solutions générales (c'est-à-dire prendre la liste des sources comme une donnée). La solution du générateur (3.) est agréable car elle filtre sur l'index de la liste source. Il est probablement aussi efficace en mémoire que 2. Les indices et la liste de résultats sont des générateurs et sont donc construits paresseusement, ce qui est probablement aussi le plus rapide si vous n'avez pas besoin de la liste de résultats en un seul morceau. Ce n'est que si la liste source pouvait être un générateur que j'irais avec l'idiome «item, i» de Paul dans enumerate (l) », car il n'y a pas de len () d'un générateur. BTW, quel type d'itérable ne fonctionnerait pas avec 1.? Générateurs?!
ThomasH

Iterable = objet avec la méthode __iter __ () retournant l'itérateur (objet avec la méthode next ())
Denis Otkidach


19

À partir du manuel: s[i:j:k] slice of s from i to j with step k

li = range(100)
sub = li[0::10]

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

13
newlist = oldlist[::10]

Cela sélectionne tous les 10 éléments de la liste.


4

Pourquoi ne pas simplement utiliser un paramètre d' étape de la fonction de plage pour obtenir:

l = range(0, 1000, 10)

A titre de comparaison, sur ma 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

3
@SilentGhost: C'est vrai, mais comme il s'agit d'une question pour débutant, la fonction de plage pourrait être ce qu'ils veulent vraiment faire, donc je pense que c'est une réponse valable. (Bien que la limite supérieure devrait être 1001, pas 1000)
Scott Griffiths

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

1
Pourquoi avez-vous la clause if alors que range (0, 1001, 10) ne prend déjà que tous les 10 éléments?
Autoplectic

4
Même commentaire ici, cela ne résout pas le problème plus général de la "manière pythonique de renvoyer la liste de chaque nième élément dans une liste plus grande" votre solution dépend du fait que les valeurs de la liste d'exemple vont de 0 à 1000 et ne tire que les éléments hors de la liste qui a une valeur divisible par 10 au lieu de chaque 10 élément.
Andre Miller

1
Eh bien, l'OP écrit: "nous avons une liste de nombres de zéro à 1000". Il n'a donc pas besoin d'une solution générale.

1
Il écrit «Disons que nous avons…», ce qui implique que ce n'est qu'un exemple. S'il voulait vraiment chaque 10e nombre sur une liste de zéro à 1000, la réponse serait la plage (0,1001,10) ou quelque chose de similaire.
Andre Miller

1

Voici une meilleure implémentation d'une compréhension de liste «tous les 10 éléments», qui n'utilise pas le contenu de la liste dans le cadre du test d'adhésion:

>>> 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']

Mais c'est encore beaucoup plus lent que d'utiliser simplement le découpage de liste.


-9

Les compréhensions de listes sont exactement faites pour cela:

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

Vous pouvez obtenir plus d'informations à leur sujet dans la documentation officielle de python: http://docs.python.org/tutorial/datastructures.html#list-comprehensions


La limite supérieure doit être 1 000 et non 10 000. Votre solution n'inclut pas la limite supérieure de 1 000 puisque la plage s'arrête à 999. +1 pour le lien vers la compréhension de la liste.

19
En fait, cela ne sort pas tous les 10 éléments, mais tous les éléments dont la valeur est divisible par 10. Dans cet exemple particulier, c'est la même chose, mais ce n'est peut-être pas le cas.
Andre Miller
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.