183

I'm wondering what is the best way to extract the first item of each sublist in a list of lists and append it to a new list. So if I have:

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

And, I want to pull out a, 1 and x and create a separate list from those.

I tried:

lst2.append(x[0] for x in lst)
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
konrad
  • 3,544
  • 4
  • 36
  • 75

9 Answers9

249

Using list comprehension:

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • 2
    List comprehension method is also the fastest, even faster than Numpy method. [jboi](https://stackoverflow.com/a/48157038/8093108)'s answer talks about performance comparison, – Qiao Zhang Jul 16 '18 at 03:22
  • 1
    @QiaoZhang: `numpy` is slower if you have to convert to a `numpy` array in the first place. If the data is stored as a `numpy` array from the get-go, it'll be much faster. – ShadowRanger Sep 15 '21 at 02:30
102

You could use zip:

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

Or, Python 3 where zip does not produce a list:

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

Or,

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

Or, (my favorite) use 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
  • 98,345
  • 23
  • 131
  • 206
  • Have not downvoted but the first code snippet (the zip) produces: "'zip' object is not subscriptable". Python 3.6 on Jupyter. – jboi Jan 07 '18 at 12:19
  • @jboi: Just wrap `list` around it first or use `next`. Thanks – dawg Jan 07 '18 at 15:32
32

Had the same issue and got curious about the performance of each solution.

Here's is the %timeit:

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

The first numpy-way, transforming the array:

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

Fully native using list comprehension (as explained by @alecxe):

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

Another native way using zip (as explained by @dawg):

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

Second numpy-way. Also explained by @dawg:

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

Surprisingly (well, at least for me) the native way using list comprehension is the fastest and about 10x faster than the numpy-way. Running the two numpy-ways without the final list saves about one µs which is still in the 10x difference.

Note that, when I surrounded each code snippet with a call to len, to ensure that Generators run till the end, the timing stayed the same.

jboi
  • 11,324
  • 4
  • 36
  • 43
  • 6
    there's a substantial overhead when creating an array. – hpaulj Aug 28 '18 at 03:12
  • 2
    agree with hpaulj, if you start off with numpy array, [:,0] is faster. Give it a go: lst = np.array([['a','b','c'], [1,2,3], ['x','y','z']]), then lst[:,0]. The conversion in the example time trials gives list comprehension an unfair advantage. So if you can, use a numpy array to store your data if speed is your ultimate goal. Numpy is almost always faster. It's built for speed. – spacedustpi Nov 14 '18 at 20:13
  • Thanks for sharing. I'm curious about `%timeit`, is this something magic from python? I mean `%timeit` is not standard python isn't it? Thanks! – Dan.py Nov 23 '22 at 16:05
16

Python includes a function called itemgetter to return the item at a specific index in a list:

from operator import itemgetter

Pass the itemgetter() function the index of the item you want to retrieve. To retrieve the first item, you would use itemgetter(0). The important thing to understand is that itemgetter(0) itself returns a function. If you pass a list to that function, you get the specific item:

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

This is useful when you combine it with map(), which takes a function as its first argument, and a list (or any other iterable) as the second argument. It returns the result of calling the function on each object in the iterable:

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

Note that map() returns a generator, so the result is passed to list() to get an actual list. In summary, your task could be done like this:

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

This is an alternative method to using a list comprehension, and which method to choose highly depends on context, readability, and preference.

More info: https://docs.python.org/3/library/operator.html#operator.itemgetter

Christian Abbott
  • 6,497
  • 2
  • 21
  • 26
  • Any idea how that compares performance-wise to list comprehensions? – Konstantin Oct 26 '20 at 10:28
  • Python's timeit module can check your specific code case (https://docs.python.org/3/library/timeit.html), List comprehensions are generally more performant. I ran timeit on a list containing 100,000 lists with the interior lists two items in length, and iterated the timeit test 10,000 times. List comprehensions took 25.2 seconds and itemgetter took 28.8 seconds. I personally find itemgetter useful in some contexts where performance isn't as important but where it happens to produce easier to read code. – Christian Abbott Oct 27 '20 at 22:37
2

Your code is almost correct. The only issue is the usage of list comprehension.

If you use like: (x[0] for x in lst), it returns a generator object. If you use like: [x[0] for x in lst], it return a list.

When you append the list comprehension output to a list, the output of list comprehension is the single element of the list.

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

Please let me know if I am incorrect.

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

print(outputlist) 

Output: ['a', 1, 'x']

m00am
  • 5,910
  • 11
  • 53
  • 69
PrabhuPrakash
  • 261
  • 2
  • 7
0

You said that you have an existing list. So I'll go with that.

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

Right now you are appending the generator object to your second list.

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

But you probably want it to be a list of first items

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

Now we appended the list of first items to the existing list. If you'd like to add the items themeselves, not a list of them, to the existing ones, you'd use list.extend. In that case we don't have to worry about adding a generator, because extend will use that generator to add each item it gets from there, to extend the current list.

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

or

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

Hendrik
  • 756
  • 6
  • 16
  • 1
    Your answer is nice and complete for what it *sounds* like the OP wants, but I think the word `append` in the question is causing confusion. It sounds like s/he simply wants the list comprehension portion of your solution. – beroe Jul 31 '14 at 06:21
0

You can extract the 1st value from a list of lists to a new list as shown below:

list_of_lists = [
    ['John', 'Anna'], [36, 24], ['Male', 'Female']
] 
           
new_list = [list[0] for list in list_of_lists] # Here

print(new_list) # ['John', 36, 'Male']

Or:

list_of_lists = [
    ['John', 'Anna'], [36, 24], ['Male', 'Female']
] 
           
new_list = [first for [first, second] in list_of_lists] # Here

print(new_list) # ['John', 36, 'Male']
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
-1

The other answer I could suggest is

lst = [['a','b','c'], [1,2,3], ['x','y','z']]
new_lst=[lst[0][0],lst[1][0],lst[2][0]]
print(new_lst)

The output comes as follows

['a', 1, 'x']

Hope this helps! Thanks!