Extrahieren Sie das erste Element jeder Unterliste

146

Ich frage mich, wie ich das erste Element jeder Unterliste in einer Liste von Listen am besten extrahieren und an eine neue Liste anhängen kann. Also wenn ich habe:

lst = [[a,b,c], [1,2,3], [x,y,z]]

und ich möchte herausziehen a, 1und , xund erstellen Sie eine separate Liste von denen.

Ich habe es versucht:

lst2.append(x[0] for x in lst)
konrad
quelle
1
Ihr Code ist fast korrekt. Das einzige Problem ist die Verwendung des Listenverständnisses.
Abhishek Mittal

Antworten:

198

Mit Liste Verständnis :

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']
Alecxe
quelle
Die Listenverständnismethode ist auch die schnellste, sogar schneller als die Numpy-Methode. jbois Antwort spricht über Leistungsvergleich,
Qiao Zhang
83

Sie könnten zip verwenden:

>>> lst=[[1,2,3],[11,12,13],[21,22,23]]
>>> zip(*lst)[0]
(1, 11, 21)

Oder Python 3, wo zipkeine Liste erstellt wird:

>>> list(zip(*lst))[0]
(1, 11, 21)

Oder,

>>> next(zip(*lst))
(1, 11, 21)

Oder (mein Favorit) benutze numpy:

>>> import numpy as np
>>> a=np.array([[1,2,3],[11,12,13],[21,22,23]])
>>> a
array([[ 1,  2,  3],
       [11, 12, 13],
       [21, 22, 23]])
>>> a[:,0]
array([ 1, 11, 21])
dawg
quelle
Habe nicht herabgestimmt, aber das erste Code-Snippet (die Zip) erzeugt: "'Zip'-Objekt ist nicht abonnierbar". Python 3.6 auf Jupyter.
Jboi
@jboi: Einfach zuerst umwickeln listoder verwenden next. Danke
dawg
20

Hatte das gleiche Problem und wurde neugierig auf die Leistung jeder Lösung.

Hier ist das %timeit:

import numpy as np
lst = [['a','b','c'], [1,2,3], ['x','y','z']]

Der erste numpy-Weg, der das Array transformiert:

%timeit list(np.array(lst).T[0])
4.9 µs ± 163 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Vollständig nativ mit Listenverständnis (wie von @alecxe erklärt):

%timeit [item[0] for item in lst]
379 ns ± 23.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Eine andere native Methode zip(wie von @dawg erklärt):

%timeit list(zip(*lst))[0]
585 ns ± 7.26 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Zweiter numpy-Weg. Auch erklärt von @dawg:

%timeit list(np.array(lst)[:,0])
4.95 µs ± 179 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Überraschenderweise (zumindest für mich) ist der native Weg mit Listenverständnis der schnellste und etwa 10x schneller als der Numpy-Weg. Das Ausführen der beiden Numpy-Wege ohne das Finale listspart ungefähr ein µs, was immer noch im 10- fachen Unterschied liegt.

Beachten Sie, dass lendas Timing gleich blieb , wenn ich jedes Code-Snippet mit einem Aufruf an umgab , um sicherzustellen, dass Generatoren bis zum Ende laufen.

jboi
quelle
4
Beim Erstellen eines Arrays entsteht ein erheblicher Aufwand.
Hpaulj
1
stimme hpaulj zu, wenn du mit numpy array beginnst, ist [:, 0] schneller. Probieren Sie es aus: lst = np.array ([['a', 'b', 'c'], [1,2,3], ['x', 'y', 'z']]), dann lst [:, 0]. Die Konvertierung in den Beispielzeitfahren verschafft dem Listenverständnis einen unfairen Vorteil. Wenn Sie können, verwenden Sie ein Numpy-Array, um Ihre Daten zu speichern, wenn Geschwindigkeit Ihr oberstes Ziel ist. Numpy ist fast immer schneller. Es ist auf Geschwindigkeit ausgelegt.
Spacedustpi
13

Python enthält eine Funktion namens itemgetter, um das Element an einem bestimmten Index in einer Liste zurückzugeben:

from operator import itemgetter

Übergeben Sie der Funktion itemgetter () den Index des Elements, das Sie abrufen möchten. Um das erste Element abzurufen, verwenden Sie itemgetter (0). Es ist wichtig zu verstehen, dass itemgetter (0) selbst eine Funktion zurückgibt. Wenn Sie dieser Funktion eine Liste übergeben, erhalten Sie das spezifische Element:

itemgetter(0)([10, 20, 30]) # Returns 10

Dies ist nützlich, wenn Sie es mit map () kombinieren, das eine Funktion als erstes Argument und eine Liste (oder eine andere iterierbare Funktion) als zweites Argument verwendet. Es gibt das Ergebnis des Aufrufs der Funktion für jedes Objekt in der iterablen Datei zurück:

my_list = [['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z']]
list(map(itemgetter(0), my_list)) # Returns ['a', 1, 'x']

Beachten Sie, dass map () einen Generator zurückgibt, sodass das Ergebnis an list () übergeben wird, um eine aktuelle Liste zu erhalten. Zusammenfassend könnte Ihre Aufgabe folgendermaßen erledigt werden:

lst2.append(list(map(itemgetter(0), lst)))

Dies ist eine alternative Methode zur Verwendung eines Listenverständnisses. Welche Methode in hohem Maße ausgewählt werden muss, hängt vom Kontext, der Lesbarkeit und den Vorlieben ab.

Weitere Informationen: https://docs.python.org/3/library/operator.html#operator.itemgetter

Christian Abbott
quelle
2

Ihr Code ist fast korrekt. Das einzige Problem ist die Verwendung des Listenverständnisses.

Wenn Sie wie folgt verwenden: (x [0] für x in lst), wird ein Generatorobjekt zurückgegeben. Wenn Sie Folgendes verwenden: [x [0] für x in lst], wird eine Liste zurückgegeben.

Wenn Sie die Ausgabe des Listenverständnisses an eine Liste anhängen, ist die Ausgabe des Listenverständnisses das einzelne Element der Liste.

lst = [["a","b","c"], [1,2,3], ["x","y","z"]]
lst2 = []
lst2.append([x[0] for x in lst])
print lst2[0]

lst2 = [['a', 1, 'x']]

lst2 [0] = ['a', 1, 'x']

Bitte lassen Sie mich wissen, wenn ich falsch bin.

Abhishek Mittal
quelle
1
lst = [['a','b','c'], [1,2,3], ['x','y','z']]
outputlist = []
for values in lst:
    outputlist.append(values[0])

print(outputlist) 

Ausgabe: ['a', 1, 'x']

PrabhuPrakash
quelle
0

Sie sagten, dass Sie eine vorhandene Liste haben. Also werde ich damit weitermachen.

>>> lst1 = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [1, 2, 3]

Im Moment hängen Sie das Generatorobjekt an Ihre zweite Liste an.

>>> lst2.append(item[0] for item in lst)
>>> lst2
[1, 2, 3, <generator object <genexpr> at 0xb74b3554>]

Aber Sie möchten wahrscheinlich, dass es eine Liste der ersten Elemente ist

>>> lst2.append([item[0] for item in lst])
>>> lst2
[1, 2, 3, ['a', 1, 'x']]

Jetzt haben wir die Liste der ersten Elemente an die vorhandene Liste angehängt. Wenn Sie die Elemente themenbezogen und nicht als Liste zu den vorhandenen Elementen hinzufügen möchten, verwenden Sie list.extend. In diesem Fall müssen wir uns keine Gedanken über das Hinzufügen eines Generators machen, da Extend diesen Generator verwendet, um jedes Element hinzuzufügen, das es von dort erhält, um die aktuelle Liste zu erweitern.

>>> lst2.extend(item[0] for item in lst)
>>> lst2
[1, 2, 3, 'a', 1, 'x']

oder

>>> lst2 + [x[0] for x in lst]
[1, 2, 3, 'a', 1, 'x']
>>> lst2
[1, 2, 3]

https://docs.python.org/3.4/tutorial/datastructures.html#more-on-lists https://docs.python.org/3.4/tutorial/datastructures.html#list-comprehensions

Hendrik
quelle
1
Ihre Antwort ist schön und komplett für das, was es klingt wie das OP will, aber ich denke , das Wort appendin der Frage Verwirrung verursacht. Es hört sich so an, als ob er / sie einfach den Teil des Listenverständnisses Ihrer Lösung haben möchte.
Beroe