【问题标题】:Remove items from list by using python list comprehensions使用 python 列表推导从列表中删除项目
【发布时间】:2016-04-01 03:22:41
【问题描述】:

我有一个整数列表,如下所示:

unculledlist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]

我想从这个列表中剔除值,使它看起来像这样:

culledlist = [0, 2, 4, 10, 12, 14, 20, 22, 24]

但我想通过使用列表推导来做到这一点。

这是我尝试剔除列表值的图形预览。如果我将列表值排列成行和列,会更容易理解。但这只是视觉上的。我不需要嵌套列表:

我可以通过使用两个嵌套循环来做到这一点:

unculledlist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]

index = 0
culledlist = []
for i in range(6):
    for j in range(5):
        if (i % 2 == 0) and (j % 2 == 0):
            culledlist.append(unculledlist[index])
        index += 1

print "culledlist: ", culledlist  # culledlist = [0, 2, 4, 10, 12, 14, 20, 22, 24]

但我想用 python 列表推导来代替。

谁能提供一个例子吗?

谢谢。

编辑:

我想使用列表推导的原因是因为我的实际unculledlist 有几百万个整数。用列表推导解决这个问题肯定会加快速度。我不关心可读性。我只是想制定一个更快的解决方案。

我不能使用 numpy 和 scipy 模块。但我可以使用itertools 模块。不确定使用 itertools 的解决方案是否比使用列表理解的解决方案更快?甚至lambda

【问题讨论】:

  • 基本就是测试row index是否偶数,item index是否偶数。
  • 从模块中导入特定的函数、类或任何时候是from module_name import something,所以在这种情况下是from itertools import ifilter,或者如果你打算使用其他东西,你可以将整个模块导入为import itertools从那里使用它作为itertools.ifilter(...)。当您执行import name1.name2 时,您正在尝试从包名称1 导入模块名称2,在这种情况下是错误的,因为ifilter 是模块中的一个函数,而不是模块本身...
  • 是的,这就是重点,ifilter 制作了一个生成器,这是一个惰性函数,仅在被要求时才产生结果,因此内存友好且仅使用少量内存,以防万一想要对每个过滤的元素进行一些复杂的演算,就像在 for 循环中一样。 itertools 模块中的每个函数都执行相同的操作。要获得整个结果,请执行 list(ifilter(...)) 或在 2.7 中使用过滤器,如果您不想要这样的功能
  • 在python 2.7中filter给出整个结果,ifilter给出一个生成器,如果这个操作的结果是你的最终结果,那么使用filter或列表理解,但如果它是一个要获得最终结果,您最好使用ifilter 或通常使用生成器来节省内存和时间。作为附加说明,如果您参与创建unculledlist,您可以使用像xrange 这样的生成器来构建它并保存在不需要的东西中使用的内存,或者如果您有完全控制权,最好直接构建culledlist无论何时……

标签: python list


【解决方案1】:

我看到这个并认为字符串操作会更简单

culled_list = [item for item in unculledlist if str(item)[-1] in ['0','2','4']]

结果仍然是整数列表

>>> culled_list
[0, 2, 4, 10, 12, 14, 20, 22, 24]

感谢 eugene y 提供了不太复杂的方法

>>> culled_list = [item for item in unculledlist if item % 10 in (0,2,4)]
>>> culled_list
[0, 2, 4, 10, 12, 14, 20, 22, 24]

【讨论】:

  • 您不需要str(),只需使用:if item % 10 in (0, 2, 4)
  • @PadraicCunningham:集合并不比三元素列表更有效。然而,使所有字符串成为数字(就像 eugeney 所做的那样)效率更高。
  • @PadraicCunningham:很确定该列表不会重复创建。 Python 字节码编译器应该只生成一次常量。这是我电脑上的计时结果:timeit.timeit('[i for i in x if i in ["2", "4", "6"]]', 'x=map(str, range(20))'): 0.16249696596059948 timeit.timeit('[i for i in x if i in y]', 'x=map(str, range(20)); y = {"2", "4", "6"}') 0.26599721203092486 所以这样做会降低性能。
  • 内联列表也超过了 2000 个元素的理解范围。
【解决方案2】:

你可以用这样的列表理解来做到这一点:

[x for i, x in enumerate(unculledlist) if (i % 6) % 2 == 0 if (i % 5) % 2 == 0]

输出是:

[0, 2, 4, 10, 12, 14, 20, 22, 24]

【讨论】:

  • 谢谢恩里科。以我的知识水平,你的方法是最容易理解的。
  • 为什么if (i % 6) % 2 == 0if (i % 5) % 2 == 0之间没有and
  • @marco:这就是列表理解的语法。您基本上必须将它们视为嵌套的 for 和 if。
  • 谢谢。但是这个if (i % 6) % 2 == 0 if (i % 5) % 2 == 0和这个if (i % 6) % 2 == 0 and if (i % 5) % 2 == 0不一样吗?
  • @marco:当然,但在列表推导中更常见的是避免和并利用语法已经做到这一点的事实。您编写多个循环和多个条件,如果它们匹配,则考虑理解的第一部分并将元素添加到结果列表中。
【解决方案3】:

您可以按 5 项块读取列表,并从每个偶数块中提取具有偶数索引的元素:

>>> [x for i, v in enumerate(range(0, len(unculledlist), 5)) if not v % 2 for x in unculledlist[v:v+5:2]]
[0, 2, 4, 10, 12, 14, 20, 22, 24]

【讨论】:

  • 谢谢@eugene y。你的方法是最快的。告诉我这个:你没有定义行数?单行中的元素数量(, 5))v+5:)。我理解正确吗? (我不是在抱怨只是问。行数不是必需的,也不是必需的)。
  • @marco:对,这将读取 5 个元素的块,直到列表用完为止。当然,您可以用变量替换数字。此外,如果您的列表很大,您可能希望在 Python2 中将 range 替换为 xrange
  • 谢谢。我将下面的 enrico.bacis 的解决方案标记为正确的解决方案,因为它最接近我对 python 的初学者理解。但你的绝对是最快的。我想知道是否存在更快的速度?再次感谢您。
【解决方案4】:
culledlist = [num for num in unculledlist if not (num / 5) % 2 and not num % 2]

当我分析模式时,我意识到包含 5、15、25 的行被排除在外。我是这样做的;

(num / 5) % 2

每行返回 1,例如 [5,6,7,8,9] 或 [15,16,17,18,19]

在其他行(从上面的等式返回 0)中,不完全排除以 0、10、20 开头的行,而是仅排除奇数值。我是这样做的;

num % 2
# Returns zero with even values.

由于第一个方程已经满足,采用基本的 num%2 可以正常工作。我没用过;

==
# A logical operator

因为 0 和 1 已经用作布尔值。

【讨论】:

  • 我并没有拒绝你,但有一个理论为什么。在 Stackoverflow,我们以向人们展示如何做事而自豪,而不仅仅是为他们做这些事。我想这就是拒绝投票的原因。
  • 你的解释当然是对的。但是我认为我使用的方法已经很清楚了,无需解释。如果我错了,我正在等待 OP 的反馈,要求解释。我宁愿被要求添加解释而不是反对
  • 虽然您认为解决方案已经足够清晰,但从新手的角度来看可能不是。另一方面,我同意你的观点,如果人们投反对票,他们应该说明原因。
  • 感谢 Rockybilly 的回复。非常好的解决方案。
猜你喜欢
  • 2022-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 1970-01-01
  • 1970-01-01
  • 2011-01-17
相关资源
最近更新 更多