Как извлечь n-й элемент из списка кортежей?

Я пытаюсь получить n-ые элементы из списка кортежей.

У меня есть что-то вроде:

elements = [(1,1,1),(2,3,7),(3,5,10)]

Я хочу извлечь только два элемента каждого кортежа в список:

seconds = [1, 3, 5]

Я знаю, что это можно сделать с помощью цикла for, но я хотел знать, есть ли другой способ, поскольку у меня есть тысячи кортежей.

Ответ 1

[x[1] for x in elements]

Ответ 2

Я знаю, что это можно сделать с помощью FOR, но я хотел знать, есть ли другой способ

Есть и другой способ. Вы также можете сделать это с помощью map и itemgetter:

>>> from operator import itemgetter
>>> map(itemgetter(1), elements)

Это все еще выполняет цикл внутри, хотя и немного медленнее, чем понимание списка:

setup = 'elements = [(1,1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))

Результаты:

Method 1: 1.25699996948
Method 2: 1.46600008011

Если вам нужно перебирать список, то использование for в порядке.

Ответ 3

Это также работает:

zip(*elements)[1]

(Я в основном публикую это, чтобы доказать себе, что я заколол zip...)

Посмотрите это в действии:

>>> help(zip)

Справка по встроенной функции zip во встроенном модуле:

застежка-молния (...)

zip (seq1 [, seq2 [...]]) → [(seq1 [0], seq2 [0]...), (...)]

Вернуть список кортежей, где каждый кортеж содержит i-й элемент из каждой последовательности аргументов. Возвращенный список усекается по длине до длины самой короткой последовательности аргументов.

>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> zip(*elements)
[(1, 2, 3), (1, 3, 5), (1, 7, 10)]
>>> zip(*elements)[1]
(1, 3, 5)
>>>

Изящная вещь, которую я узнал сегодня: используйте *list в аргументах, чтобы создать список параметров для функции...

Примечание. В Python3 zip возвращает итератор, поэтому вместо него используйте list(zip(*elements)) чтобы вернуть список кортежей.

Ответ 4

Нашел это, когда я искал, какой путь быстрее всего вытащить второй элемент из списка из 2-х кортежей. Не то, что я хотел, но выполнял те же тесты, что и третий, плюс тест zip-метода

setup = 'elements = [(1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'
method3 = 'dict(elements).values()'
method4 = 'zip(*elements)[1]'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup)
print('Method 3: ' + str(t.timeit(100)))
t = timeit.Timer(method4, setup)
print('Method 4: ' + str(t.timeit(100)))

Method 1: 0.618785858154
Method 2: 0.711684942245
Method 3: 0.298138141632
Method 4: 1.32586884499

Так что в два раза быстрее, если у вас есть пара 2 кортежей, чтобы просто преобразовать в dict и принять значения.

Ответ 5

map (lambda x:(x[1]),elements)

Ответ 6

Времена для Python 3.6 для извлечения второго элемента из списка из двух кортежей.

Кроме того, добавлен метод массива numpy, который проще для чтения (но, возможно, проще, чем понимание списка).

from operator import itemgetter
elements = [(1,1) for _ in range(100000)]

%timeit second = [x[1] for x in elements]
%timeit second = list(map(itemgetter(1), elements))
%timeit second = dict(elements).values()
%timeit second = list(zip(*elements))[1]
%timeit second = np.array(elements)[:,1]

и сроки:

list comprehension:  4.73 ms ± 206 µs per loop
list(map):           5.3 ms ± 167 µs per loop
dict:                2.25 ms ± 103 µs per loop
list(zip)            5.2 ms ± 252 µs per loop
numpy array:        28.7 ms ± 1.88 ms per loop

Обратите внимание, что map() и zip() больше не возвращают список, следовательно, явное преобразование.

Ответ 7

Использование islice и chain.from_iterable:

>>> from itertools import chain, islice
>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> list(chain.from_iterable(islice(item, 1, 2) for item in elements))
[1, 3, 5]

Это может быть полезно, когда вам нужно более одного элемента:

>>> elements = [(0, 1, 2, 3, 4, 5), 
                (10, 11, 12, 13, 14, 15), 
                (20, 21, 22, 23, 24, 25)]
>>> list(chain.from_iterable(islice(tuple_, 2, 5) for tuple_ in elements))
[2, 3, 4, 12, 13, 14, 22, 23, 24]