[python] How to extract the n-th elements from a list of tuples?

I'm trying to obtain the n-th elements from a list of tuples.

I have something like:

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

I wish to extract only the second elements of each tuple into a list:

``````seconds = [1, 3, 5]
``````

I know that it could be done with a `for` loop but I wanted to know if there's another way since I have thousands of tuples.

This question is related to `python` `list` `tuples`

This also works:

``````zip(*elements)[1]
``````

(I am mainly posting this, to prove to myself that I have groked `zip`...)

See it in action:

``````>>> help(zip)
``````

Help on built-in function zip in module builtin:

zip(...)

zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.

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

Neat thing I learned today: Use `*list` in arguments to create a parameter list for a function...

Note: In Python3, `zip` returns an iterator, so instead use `list(zip(*elements))` to return a list of tuples.

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

Found this as I was searching for which way is fastest to pull the second element of a 2-tuple list. Not what I wanted but ran same test as shown with a 3rd method plus test the zip method

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

So over twice as fast if you have a 2 tuple pair to just convert to a dict and take the values.

Timings for Python 3.6 for extracting the second element from a 2-tuple list.

Also, added `numpy` array method, which is simpler to read (but arguably simpler than the list comprehension).

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

and the timings:

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

Note that `map()` and `zip()` do not return a list anymore, hence the explicit conversion.

I know that it could be done with a FOR but I wanted to know if there's another way

There is another way. You can also do it with map and itemgetter:

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

This still performs a loop internally though and it is slightly slower than the list comprehension:

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

Results:

```Method 1: 1.25699996948
Method 2: 1.46600008011
```

If you need to iterate over a list then using a `for` is fine.

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

This can be useful when you need more than one element:

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