Wyodrębnij pierwszą pozycję z każdej podlisty


146

Zastanawiam się, jaki jest najlepszy sposób na wyodrębnienie pierwszej pozycji z każdej podlisty na liście list i dołączenie jej do nowej listy. Więc jeśli mam:

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

i chcę wyciągnąć a, 1a xi utworzyć osobną listę z nich.

Próbowałem:

lst2.append(x[0] for x in lst)

1
Twój kod jest prawie poprawny. Jedynym problemem jest użycie rozumienia list.
Abhishek Mittal

Odpowiedzi:


198

Korzystanie ze rozumienia list :

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']

Zrozumienie list jest również najszybsze, nawet szybsze niż metoda Numpy. Odpowiedź jboi mówi o porównaniu wydajności,
Qiao Zhang

83

Możesz użyć zip:

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

Lub Python 3, gdzie zipnie tworzy listy:

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

Lub,

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

Lub (mój ulubiony) użyj 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])

Nie poddano głosowania w dół, ale pierwszy fragment kodu (plik zip) daje: „Obiekt„ zip ”nie jest indeksowany”. Python 3.6 na Jupyter.
jboi,

@jboi: Po prostu owiń listgo najpierw lub użyj next. Dzięki
dawg

20

Miałem ten sam problem i zaciekawiło mnie działanie każdego rozwiązania.

Oto %timeit:

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

Pierwszy numpy-way, transformujący tablicę:

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

W pełni natywny przy użyciu funkcji list (zgodnie z wyjaśnieniem @alecxe):

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

Inny natywny sposób użycia zip(jak wyjaśniono w @dawg):

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

Drugi odrętwienie. Wyjaśnione również przez @dawg:

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

Zaskakująco (przynajmniej dla mnie) natywny sposób korzystania ze rozumienia list jest najszybszy i około 10 razy szybszy niż metoda numpy. Uruchomienie dwóch numpy-way bez finału listoszczędza około jednego µs, co nadal jest 10 -krotną różnicą.

Zauważ, że kiedy otoczyłem każdy fragment kodu wezwaniem do len, aby upewnić się, że generatory działają do końca, czas pozostał taki sam.


4
podczas tworzenia tablicy występuje znaczne obciążenie.
hpaulj

1
zgadzam się z hpaulj, jeśli zaczniesz od numpy array, [:, 0] jest szybsze. Spróbuj: lst = np.array ([['a', 'b', 'c'], [1,2,3], ['x', 'y', 'z']]), następnie lst [:, 0]. Konwersja w przykładowych próbach czasowych daje zrozumienie listy nieuczciwej przewagi. Więc jeśli możesz, użyj tablicy numpy do przechowywania danych, jeśli prędkość jest Twoim ostatecznym celem. Numpy jest prawie zawsze szybszy. Jest zbudowany z myślą o szybkości.
spacedustpi

13

Python zawiera funkcję o nazwie itemgetter, która zwraca element pod określonym indeksem na liście:

from operator import itemgetter

Przekaż funkcji itemgetter () indeks elementu, który chcesz pobrać. Aby pobrać pierwszy element, możesz użyć itemgetter (0). Ważne jest, aby zrozumieć, że sam itemgetter (0) zwraca funkcję. Jeśli przekażesz listę do tej funkcji, otrzymasz konkretną pozycję:

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

Jest to przydatne, gdy łączysz ją z map (), która przyjmuje funkcję jako pierwszy argument i listę (lub dowolną inną iterowalną) jako drugi argument. Zwraca wynik wywołania funkcji na każdym obiekcie w iterowalnej:

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

Zauważ, że map () zwraca generator, więc wynik jest przekazywany do list () w celu uzyskania aktualnej listy. Podsumowując, twoje zadanie można wykonać w następujący sposób:

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

Jest to metoda alternatywna w stosunku do rozumienia list, a wybór metody zależy w dużym stopniu od kontekstu, czytelności i preferencji.

Więcej informacji: https://docs.python.org/3/library/operator.html#operator.itemgetter


2

Twój kod jest prawie poprawny. Jedynym problemem jest użycie rozumienia list.

Jeśli używasz like: (x [0] for x in lst), zwraca obiekt generatora. Jeśli użyjesz like: [x [0] for x in lst], zwraca listę.

Kiedy dołączasz wynik zrozumienia listy do listy, wynikiem zrozumienia listy jest pojedynczy element listy.

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

Daj mi znać, jeśli się mylę.


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

print(outputlist) 

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


0

Powiedziałeś, że masz istniejącą listę. Więc pójdę z tym.

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

W tej chwili dodajesz obiekt generatora do drugiej listy.

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

Ale prawdopodobnie chcesz, aby była to lista pierwszych pozycji

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

Teraz dołączyliśmy listę pierwszych pozycji do istniejącej listy. Jeśli chcesz dodać same elementy, a nie ich listę, do istniejących, użyj list.extend. W takim przypadku nie musimy się martwić o dodanie generatora, ponieważ rozszerzenie użyje tego generatora do dodania każdego elementu, który stamtąd otrzyma, w celu rozszerzenia bieżącej listy.

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

lub

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


1
Twoja odpowiedź jest miła i pełna za to, co brzmi jak PO chce, ale myślę, że słowo appendw pytaniu jest przyczyną nieporozumień. Wygląda na to, że po prostu chce, aby część Twojego rozwiązania obejmowała zrozumienie listy.
beroe
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.