Ответ 1
[x[1] for x in elements]
Я пытаюсь получить n-ые элементы из списка кортежей.
У меня есть что-то вроде:
elements = [(1,1,1),(2,3,7),(3,5,10)]
Я хочу извлечь только два элемента каждого кортежа в список:
seconds = [1, 3, 5]
Я знаю, что это можно сделать с помощью цикла for
, но я хотел знать, есть ли другой способ, поскольку у меня есть тысячи кортежей.
[x[1] for x in elements]
Я знаю, что это можно сделать с помощью 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
в порядке.
Это также работает:
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))
чтобы вернуть список кортежей.
Нашел это, когда я искал, какой путь быстрее всего вытащить второй элемент из списка из 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 и принять значения.
map (lambda x:(x[1]),elements)
Времена для 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()
больше не возвращают список, следовательно, явное преобразование.
Использование 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]