Pythonische Methode, um die Liste aller n-ten Elemente in einer größeren Liste zurückzugeben


170

Angenommen, wir haben eine Liste mit Zahlen von 0 bis 1000. Gibt es eine pythonische / effiziente Möglichkeit, eine Liste des ersten und jedes nachfolgenden 10. Elements zu erstellen, d [0, 10, 20, 30, ... ]. H.

Ja, ich kann dies mit einer for-Schleife tun, aber ich frage mich, ob es einen besseren Weg gibt, dies zu tun, vielleicht sogar in einer Zeile?

Antworten:


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

Beachten Sie, dass dies etwa 100-mal schneller ist als das Schleifen und Überprüfen eines Moduls für jedes Element:

$ 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
Sicher, Listenverständnisse sind im Allgemeinen leistungsfähiger. OTOH, die Frage setzt eine vorhandene Liste und in diesem Fall funktioniert ein Slice einwandfrei.
Ned Deily

Ich habe dies unten in den Antworten zum Listenverständnis kommentiert. Seien Sie vorsichtig mit "if x% 10 == 0". Es funktioniert nur mit diesem speziellen Listenbeispiel, aber wenn die Eingabeliste zum Beispiel l = Bereich (0,1000,2) ist, wird nicht jedes 10. Element herausgezogen.
Andre Miller

12
@ Andrew: sehr wahr. Dies ist also ein Beispiel für eine bescheidene Sprachfunktion, den Slice-Operator, der sich in diesem Fall herausstellt (1), um das Erreichen der richtigen Ergebnisse zu erleichtern. (2) führt zu einem prägnanteren Ausdruck; und (3) zufällig 2 Größenordnungen schneller ist. (1) ist natürlich bei weitem das wichtigste Anliegen, aber dank der sorgfältigen Gestaltung und Implementierung der Sprache erhalten Sie alle drei zum Preis von 1. Schöne Fragen und Antworten.
Ned Deily

2
Das 0ist überflüssig in l[0::10]. l[::10]ist besser lesbar, weniger verwirrend.
Konstantin Schubert

Ich bin überrascht vom Leistungsvergleich 0,5 Sekunden für das Listenverständnis und 0,4 Sekunden für das Listen-Slice. Scheint sehr langsam zu sein, warum das Schneiden von Listen 100.000 Schleifen für eine Liste der Größe 1 Tausend benötigt!?
Damo

57
  1. source_list[::10] ist das offensichtlichste, aber dies funktioniert nicht für iterierbare und ist für große Listen nicht speichereffizient.
  2. itertools.islice(source_sequence, 0, None, 10) funktioniert für jedes iterable und ist speichereffizient, ist aber wahrscheinlich nicht die schnellste Lösung für große Listen und große Schritte.
  3. (source_list[i] for i in xrange(0, len(source_list), 10))

1
+1 Beste Antwort, IMO. Alle drei Vorschläge stellen allgemeine Lösungen dar (dh nehmen Sie die Quellenliste als gegeben). Die Generatorlösung (3.) ist nett, da sie nach dem Index der Quellliste filtert. Es ist wahrscheinlich so speichereffizient wie 2. Sowohl die Indizes als auch die Ergebnisliste sind Generatoren und daher träge aufgebaut. Dies ist wahrscheinlich auch die schnellste, wenn Sie die Ergebnisliste nicht in einem einzelnen Block benötigen. Nur wenn die Quellenliste ein Generator sein könnte, würde ich mit Pauls "item, i in enumerate (l)" Idiom gehen, da es keine len () eines Generators gibt. Übrigens, welche Art von Iterable würde mit 1. nicht funktionieren? Generatoren?!
ThomasH

Iterable = Objekt mit __iter __ () -Methode, das Iterator zurückgibt (Objekt mit next () -Methode)
Denis Otkidach


18

Aus dem Handbuch: 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]

Dies wählt jedes 10. Element der Liste aus.


4

Warum nicht auch einen Schrittparameter der Bereichsfunktion verwenden, um Folgendes zu erhalten:

l = range(0, 1000, 10)

Zum Vergleich auf meiner Maschine:

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: Das stimmt, aber da dies eine Anfängerfrage ist, könnte die Bereichsfunktion das sein, was sie wirklich wollen, also denke ich, dass es eine gültige Antwort ist. (Obwohl die Obergrenze 1001 sein sollte, nicht 1000)
Scott Griffiths

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

1
Warum haben Sie die if-Klausel, wenn der Bereich (0, 1001, 10) bereits nur jedes 10. Element akzeptiert?
Autoplektische

4
Gleicher Kommentar hier, dies löst nicht das allgemeinere Problem der "pythonischen Methode, die Liste aller n-ten Elemente in einer größeren Liste zurückzugeben". Ihre Lösung hängt von der Tatsache ab, dass die Werte der Beispielliste 0 bis 1000 sind und nur Elemente abrufen aus der Liste, deren Wert durch 10 anstelle jedes 10. Elements teilbar ist.
Andre Miller

1
Nun, das OP schreibt: "Wir haben eine Liste von Zahlen von Null bis 1000". Er braucht also keine allgemeine Lösung.

1
Er schreibt "Sag, wir haben ...", was impliziert, dass es nur ein Beispiel ist. Wenn er wirklich jede 10. Zahl aus einer Liste von Null bis 1000 haben wollte, wäre die Antwort Bereich (0,1001,10) oder ähnliches.
Andre Miller

1

Hier ist eine bessere Implementierung eines Listenverständnisses für "alle 10 Elemente", bei dem der Listeninhalt nicht als Teil des Mitgliedschaftstests verwendet wird:

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

Dies ist jedoch immer noch viel langsamer als nur das Aufteilen von Listen.


-9

Listenverständnisse sind genau dafür gemacht:

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

Weitere Informationen dazu finden Sie in der offiziellen Python-Dokumentation: http://docs.python.org/tutorial/datastructures.html#list-comprehensions


Die Obergrenze sollte 1000 sein, nicht 10000. Ihre Lösung enthält nicht die Obergrenze von 1000, da der Bereich bei 999 endet. +1 für den Link zum Listenverständnis.

18
Dies zieht nicht jedes 10. Element heraus, sondern jedes Element, dessen Wert durch 10 teilbar ist. In diesem Beispiel ist es dasselbe, aber möglicherweise nicht.
Andre Miller
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.