使用Python列表推导式从列表中删除项目。

10

我有一个整数列表,内容如下:

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]

但我想通过使用列表推导式来实现这一点。

这是我试图整理列表值的图形预览。如果我将列表值排列成行和列,这将更容易理解。但这只是视觉效果。我不需要嵌套的列表:enter image description here

我可以通过使用两个嵌套循环来实现:

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


基本上,测试行索引是否为偶数且项目索引是否为偶数。 - Malik Brahimi
@Copperfield 谢谢。有趣的是,我在尝试运行import itertools.ifilter后,在Python 2.7和IronPython 2.7中都收到了ImportError: No module named ifilter的消息。你知道为什么会发生这种情况吗? - marco
1
要从模块中导入特定的函数、类或其他内容,可以使用 from module_name import something 的语法,因此在这种情况下,应该使用 from itertools import ifilter。或者,如果您计划使用该模块中的其他内容,则可以将整个模块导入为 import itertools,然后使用 itertools.ifilter(...)。当您执行 import name1.name2 时,您正在尝试从包名1中导入模块name2,但在这种情况下是错误的,因为ifilter是模块中的一个函数而不是模块本身... - Copperfield
1
是的,这就是重点,ifilter 生成器,它是一种惰性函数,只有在被要求时才产生结果,因此它对内存友好,并且仅使用少量内存,在需要对每个过滤后的元素进行复杂计算(例如在 for 循环中)时非常有用。itertools 模块中的每个函数都是如此。要获取整个结果,请使用 list(ifilter(...)) 或者如果您不需要这样的功能,则在 2.7 中使用 filter。 - Copperfield
1
在Python 2.7中,filter会返回整个结果,而ifilter则返回一个生成器。如果该操作的结果是您的最终结果,则使用filter或列表推导式;但如果它是获取最终结果的步骤,则最好使用ifilter或通常使用生成器来节省内存和时间。另外,如果您参与创建unculledlist,可以使用像xrange这样的生成器来构建它并节省不必要的内存,或者更好的方法是,如果您完全控制了何时进行操作,直接构建culledlist - Copperfield
显示剩余7条评论
4个回答

7
我看到这个并认为字符串操纵会是更简单的方法。
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]

1
你不需要使用 str(),只需使用:if item % 10 in (0, 2, 4) - Eugene Yarmash
1
@PadraicCunningham:一个集合并不比一个三元素列表更高效。然而,将所有字符串转换为数字(就像Eugeney所做的那样)才更高效。 - Fengyang Wang
1
@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因此,这样做会有性能损失。 - Fengyang Wang
内联列表在包含2000个元素的情况下,比起推导式外部的集合更具优势。 - Fengyang Wang
让我们在聊天中继续这个讨论 - Fengyang Wang

3
您可以使用类似于以下的列表推导式来完成它:
[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
1
@marco:这就是列表推导式的语法。你可以把它们看作嵌套的for循环和if语句。 - enrico.bacis
1
谢谢。但是这个 if (i % 6) % 2 == 0 if (i % 5) % 2 == 0 不就等同于这个:if (i % 6) % 2 == 0 and if (i % 5) % 2 == 0 吗? - marco
@marco:当然可以,但在列表推导中,通常避免使用“and”,而是利用语法已经实现的功能。您可以编写多个循环和多个条件语句,如果它们匹配,则将考虑推导式的第一部分,并将元素添加到结果列表中。 - enrico.bacis
-谢谢enrico.bacis -谢谢@PadraicCunningham。您能否写出整个表达式?我不明白哪一部分是多余的。 - marco
显示剩余3条评论

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
1
@marco:没错,这段程序会读取由5个元素组成的块,直到列表被完全读取。当然你也可以把数字替换为变量。如果你有一个很长的列表,在 Python2 中你可能需要将 range 替换为 xrange - Eugene Yarmash
谢谢。我已经将enrico.bacis的解决方案标记为正确答案,因为它最接近我的Python初学者理解。但是你的确是最快的一个。我想知道是否存在更快的方法? 再次感谢。 - marco

3
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、10、20开始的行(以上方程式返回0),并没有全部排除,而是仅排除了奇数值。我使用以下代码实现:

num % 2
# Returns zero with even values.

由于第一个方程已经满足,取基本的num%2就可以了。我没有使用任何分号。

==
# A logical operator

由于0和1已经充当布尔值,因此不需要解释。


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Hai Vu
当然,你说的关于解释的是对的。但是我认为我使用的方法已经很清楚了,不需要解释。如果我错了,我会等待OP的反馈,要求解释。我宁愿被要求添加解释,而不是被点踩。 - Rockybilly
1
虽然你认为解决方案已经足够清晰,但对于新手来说可能并不清晰。另一方面,我同意如果人们要进行负面评价,他们应该说明原因。 - Hai Vu
1
谢谢您的回复,Rockybilly。非常好的解决方案。 - marco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接