Извлечь первый элемент каждого подсписка

146

Мне интересно, как лучше всего извлечь первый элемент каждого подсписка в списке списков и добавить его в новый список. Так что если у меня есть:

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

и я хочу , чтобы вытащить a, 1а xи создать отдельный список из них.

Я попытался:

lst2.append(x[0] for x in lst)
Konrad
источник
1
Ваш код почти правильный. Единственная проблема - использование понимания списка.
Абхишек Миттал

Ответы:

198

Используя понимание списка :

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']
alecxe
источник
Метод понимания списка также самый быстрый, даже быстрее, чем метод Numpy. Ответ jboi говорит о сравнении производительности,
Цяо Чжан
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])
Dawg
источник
Не понизили, но первый фрагмент кода (zip) выдает: «Объект zip не является подписным». Python 3.6 на Jupyter.
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, чтобы убедиться, что Генераторы работают до конца, время остается неизменным.

jboi
источник
4
Существенные накладные расходы при создании массива.
hpaulj
1
согласен с hpaulj, если вы начинаете с массива numpy, [:, 0] быстрее. Попробуйте: lst = np.array ([['a', 'b', 'c'], [1,2,3], ['x', 'y', 'z']]), затем lst [:, 0]. Преобразование в примерные испытания времени дает понимание списка несправедливое преимущество. Поэтому, если вы можете, используйте массив данных для хранения ваших данных, если ваша конечная цель - скорость. Numpy почти всегда быстрее. Он построен для скорости.
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 () возвращает генератор, поэтому результат передается в list () для получения фактического списка. Таким образом, ваша задача может быть выполнена следующим образом:

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

Это альтернативный метод для использования понимания списка, и какой метод выбрать сильно зависит от контекста, читаемости и предпочтений.

Дополнительная информация: https://docs.python.org/3/library/operator.html#operator.itemgetter

Кристиан Эбботт
источник
2

Ваш код почти правильный. Единственная проблема - использование понимания списка.

Если вы используете like: (x [0] для x в lst), он возвращает объект генератора. Если вы используете вроде: [x [0] для x в 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']

PrabhuPrakash
источник
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. В этом случае нам не нужно беспокоиться о добавлении генератора, потому что расширение будет использовать этот генератор для добавления каждого элемента, который он получает оттуда, для расширения текущего списка.

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

Хендрик
источник
1
Ваш ответ хороший и полный для того, что звучит так, как хочет ОП, но я думаю, что слово appendв вопросе вызывает путаницу. Похоже, он / она просто хочет, чтобы часть вашего решения содержала понимание списка.
Беро