Витягніть перший елемент кожного підспису


146

Мені цікаво, який найкращий спосіб вилучити перший список кожного підпису в списку списків і додати його до нового списку. Тож якщо я маю:

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

і я хочу , щоб витягнути a, 1а xй створити окремий список з них.

Я намагався:

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

1
Ваш код майже правильний. Єдине питання - використання розуміння списку.
Абхішек Міттал

Відповіді:


198

Використання розуміння списку :

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

Метод розуміння списку також є найшвидшим, навіть швидшим, ніж метод Numpy. Відповідь jboi говорить про порівняння продуктивності,
Qiao Zhang

83

Ви можете використовувати zip:

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

Або Python 3, де zipне створюється список:

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

Або,

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

Або (мій улюблений) використовуйте 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])

Не заперечували, але перший фрагмент коду (zip) видає: "zip" об'єкт не піддається підпису ". Python 3.6 на Юпітері.
jboi

@jboi: просто listспочатку оберніть його чи використовуйте next. Спасибі
dawg

20

Виникло те саме питання та цікаво ставилося до виконання кожного рішення.

Ось %timeit:

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

Перший нульовий шлях, що перетворює масив:

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

Цілком рідний, використовуючи розуміння списку (як пояснив @alecxe):

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

Ще один власний спосіб використання zip(як пояснив @dawg):

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

Другий нудотний шлях. Також пояснив @dawg:

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

Дивно (ну, принаймні, для мене) рідний спосіб, який використовує розуміння списку, є найшвидшим і приблизно в 10 разів швидшим, ніж нумерований. Запуск двох нумерованих шляхів без остаточного listекономить приблизно один мкс, що все ще знаходиться в 10-кратній різниці.

Зауважте, що коли я оточував кожний фрагмент коду із закликом до len, щоб гарантувати, що Генератори працюватимуть до кінця, терміни залишилися колишніми.


4
при створенні масиву істотні накладні витрати.
hpaulj

1
погодьтеся з hpaulj, якщо ви почнете з numpy масиву, [:, 0] швидше. Дайте йому: lst = np.array ([['a', 'b', 'c'], [1,2,3], ['x', 'y', 'z']]), тоді lst [:, 0]. Перетворення в прикладних випробуваннях часу дає розуміння списку несправедливою перевагою. Тож якщо ви можете, використовуйте масивний масив, щоб зберігати свої дані, якщо швидкість - ваша кінцева мета. Пустотіла майже завжди швидша. Він побудований для швидкості.
spacedustpi

13

Python включає функцію, яку називають itemgetter, щоб повернути елемент у певному індексі у списку:

from operator import itemgetter

Передайте функцію itemgetter () індекс елемента, який ви хочете отримати. Щоб отримати перший елемент, ви використовуєте itemgetter (0). Важливо розуміти, що itemgetter (0) сам повертає функцію. Якщо ви передаєте список цій функції, ви отримаєте конкретний елемент:

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

Це корисно, коли ви поєднуєте його з map (), який приймає функцію як перший аргумент, і список (або будь-який інший ітерабельний) як другий аргумент. Він повертає результат виклику функції на кожному об'єкті в ітерабелі:

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

Зауважте, що map () повертає генератор, тому результат передається в список (), щоб отримати фактичний список. Підсумовуючи це, ваше завдання можна зробити так:

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

Це альтернативний метод використання списку розуміння, і який метод вибрати сильно залежить від контексту, читабельності та уподобань.

Більше інформації: https://docs.python.org/3/library/operator.html#operator.itemgetter


2

Ваш код майже правильний. Єдине питання - використання розуміння списку.

Якщо ви використовуєте like: (x [0] for x in lst), він повертає об'єкт-генератор. Якщо ви використовуєте: [x [0] для x in lst], він повертає список.

Коли ви додаєте висновок розуміння списку до списку, висновок розуміння списку є єдиним елементом списку.

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

Будь ласка, повідомте мене, якщо я невірний.


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

print(outputlist) 

Вихід: ['a', 1, 'x']


0

Ви сказали, що у вас є список. Тож я піду з цим.

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

Зараз ви додаєте об’єкт генератора до свого другого списку.

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

Але ви, мабуть, хочете, щоб це був список перших пунктів

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

Тепер ми додали список перших елементів до наявного списку. Якщо ви хочете додати елементи теми самі, а не їх список, до існуючих, ви використовуєте list.extend. У такому випадку нам не потрібно турбуватися про додавання генератора, тому що Extend використовуватиме цей генератор для додавання кожного пункту, який він отримує звідти, для розширення поточного списку.

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

або

>>> 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-com порозуміння


1
Ваша відповідь є приємною та повною для того, що це звучить так, як хоче ОП, але я думаю, що слово appendу питанні викликає плутанину. Це здається, що s / він просто хоче частину вашого розуміння списку.
beroe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.