提取Python每个子列表的第一个项
我在想,怎么才能从一个包含多个子列表的列表中提取每个子列表的第一个元素,然后把这些元素放到一个新的列表里。比如说,如果我有:
lst = [[a,b,c], [1,2,3], [x,y,z]]
我想要把 a
、1
和 x
拿出来,放到一个单独的列表里。
我试过:
lst2.append(x[0] for x in lst)
9 个回答
你的代码差不多是对的。唯一的问题在于你使用了列表推导式。
如果你写成这样: (x[0] for x in lst),它会返回一个生成器对象。
而如果你写成这样:[x[0] for x in 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']
如果我说错了,请告诉我。
Python 有一个叫做 itemgetter 的函数,可以用来获取列表中特定位置的项目:
from operator import itemgetter
你只需要把你想要获取的项目的索引传给 itemgetter() 函数。如果你想获取第一个项目,就用 itemgetter(0)。重要的是要明白,itemgetter(0) 本身返回的是一个函数。如果你把一个列表传给这个函数,就能得到那个特定的项目:
itemgetter(0)([10, 20, 30]) # Returns 10
这个功能在和 map() 函数结合使用时特别有用。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
我也遇到过同样的问题,所以我对每种解决方案的性能产生了好奇。
这里是使用 %timeit
测试的结果:
import numpy as np
lst = [['a','b','c'], [1,2,3], ['x','y','z']]
第一种使用numpy的方法,变换数组:
%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)
第二种numpy的方法,也由@dawg解释:
%timeit list(np.array(lst)[:,0])
4.95 µs ± 179 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
令人惊讶的是(至少对我来说),使用列表推导的原生方法是最快的,速度大约是numpy方法的10倍。运行这两种numpy方法时,如果不加最后的 list
,可以节省大约1微秒,但这仍然保持在10倍的差距内。
需要注意的是,当我在每个代码片段周围加上 len
的调用,以确保生成器能运行到最后时,计时结果保持不变。
你可以使用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])
使用列表推导式:
>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']