提取每个子列表的第一项

Posted

技术标签:

【中文标题】提取每个子列表的第一项【英文标题】:Extract first item of each sublist 【发布时间】:2014-09-22 21:23:14 【问题描述】:

我想知道提取列表列表中每个子列表的第一项并将其附加到新列表的最佳方法是什么。所以如果我有:

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

我想提取 a1x 并从中创建一个单独的列表。

我试过了:

lst2.append(x[0] for x in lst)

【问题讨论】:

您的代码几乎是正确的。唯一的问题是列表理解的使用。 另请参阅***.com/questions/25082410/…,了解更一般的问题和解决方案。 【参考方案1】:

使用list comprehension:

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']

【讨论】:

列表推导方法也是最快的,甚至比 Numpy 方法还要快。 jboi的回答讲性能比较, @QiaoZhang: numpy 如果您必须首先转换为numpy 数组,则速度较慢。如果从一开始就将数据存储为numpy 数组,速度会快得多。【参考方案2】:

您的代码几乎是正确的。唯一的问题是列表理解的使用。

如果你使用 like: (x[0] for x in lst),它会返回一个生成器对象。 如果你使用 like: [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']

如果我不正确,请告诉我。

【讨论】:

【参考方案3】:

你说你有一个现有的列表。所以我会同意的。

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

现在您正在将生成器对象附加到您的第二个列表中。

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

但您可能希望它是第一个项目的列表

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

现在我们将第一个项目的列表附加到现有列表中。如果您想将项目本身而不是它们的列表添加到现有项目中,则可以使用 list.extend。在这种情况下,我们不必担心添加生成器,因为 extend 将使用该生成器添加从那里获取的每个项目,以扩展当前列表。

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

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

【讨论】:

你的回答很好,很完整,因为它 听起来 就像 OP 想要的那样,但我认为问题中的 append 一词会引起混淆。听起来他/她只是想要您的解决方案的列表理解部分。【参考方案4】:

你可以使用 zip:

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

或者,zip 不生成列表的 Python 3:

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

【讨论】:

尚未投票,但第一个代码 sn-p(zip)产生:“'zip' 对象不可下标”。 Jupyter 上的 Python 3.6。 @jboi:只需先将list 包裹起来或使用next。谢谢【参考方案5】:

Python 包含一个名为 itemgetter 的函数,用于返回列表中特定索引处的项目:

from operator import itemgetter

将要检索的项目的索引传递给 itemgetter() 函数。要检索第一项,您将使用 itemgetter(0)。要理解的重要一点是 itemgetter(0) 本身返回一个函数。如果您将列表传递给该函数,您将获得特定项目:

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

当你将它与 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

【讨论】:

知道如何将性能方面与列表推导进行比较吗? Python 的 timeit 模块可以检查您的特定代码案例 (docs.python.org/3/library/timeit.html),列表推导通常性能更高。我在一个包含 100,000 个列表的列表上运行 timeit,其中内部列表长度为两个项目,并迭代 timeit 测试 10,000 次。列表推导耗时 25.2 秒,itemgetter 耗时 28.8 秒。我个人认为 itemgetter 在性能不那么重要但它恰好可以生成更易于阅读的代码的情况下很有用。【参考方案6】:
lst = [['a','b','c'], [1,2,3], ['x','y','z']]
outputlist = []
for values in lst:
    outputlist.append(values[0])

print(outputlist) 

输出:['a', 1, 'x']

【讨论】:

【参考方案7】:

遇到同样的问题并对每个解决方案的性能感到好奇。

这是%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 倍。在没有最终 list 的情况下运行两种 numpy 方式可以节省大约 1 µs,但仍然相差 10 倍。

请注意,当我用调用len 包围每个代码sn-p 以确保生成器运行到最后时,时间保持不变。

【讨论】:

创建数组时会产生大量开销。 同意 hpaulj,如果从 numpy 数组开始,[:,0] 会更快。试一试:lst = np.array([['a','b','c'], [1,2,3], ['x','y','z']]),然后是 lst[:,0]。示例计时赛中的转换为列表理解提供了不公平的优势。因此,如果可以,如果速度是您的最终目标,请使用 numpy 数组来存储数据。 Numpy 几乎总是更快。它专为速度而生。

以上是关于提取每个子列表的第一项的主要内容,如果未能解决你的问题,请参考以下文章

第一次使用markdown

如何在org-mode中创建多级有序(编号)普通列表?

在Scala中为列表中的每一行获取元组的第一项

MarkDown语法详解

如何提取每个子列表中每个元组的第一个元素?

在单个 SELECT 中获取某个组的第一项