【问题标题】:Python List Comprehension: Using "if" Statement on Result of the ComprehensionPython 列表理解:对理解结果使用“if”语句
【发布时间】:2017-11-21 03:23:36
【问题描述】:

您能否根据推导中转换的结果过滤列表推导?

例如,假设您要删除列表中的每个字符串,并删除只是空格的字符串。我可以轻松做到以下几点:

filter(None, [x.strip() for x in str_list])

但这会遍历列表两次。或者,您可以执行以下操作:

[x.strip() for x in str_list if x.strip()]

但是那个实现会执行两次strip。我也可以使用生成器:

for x in str_list:
   x = x.strip()
   if x:
      yield x

但现在这是一堆代码。有没有办法做到上述(1)只迭代一次; (2) 只进行一次变换; (3) 在单个列表理解中?上面的例子是一个玩具例子,但我想用更长的列表和非平凡的转换来做到这一点。

更新:我使用的是 Python 2.7.X,并且更喜欢其中的答案,但如果 Python 3 有一些新功能可以让这变得简单,我很乐意了解它们,因为好吧。

【问题讨论】:

  • 遗憾的是没有。我能想到的最接近的方法是双重包装 - [x for x in (y.strip() for y in str_list) if x] 从技术上讲,它会遍历列表两次 - 但至少因为内部使用的是生成器,它不会使用太多额外的内存。
  • 什么版本的 Python?这在这里非常重要。
  • @MadPhysicist 好点,见更新
  • 只需编写一个for循环并分配给一个临时变量。那将是 Pythonic 的方式。多写几行代码不会害死你。依赖嵌套生成器表达式和其他变通方法与优雅的 IMO 相反。

标签: python list list-comprehension


【解决方案1】:

不要将列表传递给filter,传递一个生成器表达式,它只会被迭代一次:

filter(None, (x.strip() for x in str_list))

这与使用嵌套生成器的想法完全相同

[y for y in (x.strip() for x in str_list) if y]

这两种情况都依赖于生成器的惰性求值:str_list 的每个元素将在创建相应的输出元素时只被处理一次。不会生成中间列表。

理解方法非常适合像这样的小型一次性转换。在我看来,即使是这里的简单示例(在转换后进行过滤)也在推动可读性的极限。对于任何重要的转换和过滤器序列,我建议使用for 循环。

【讨论】:

  • 我一直认为filter(None, iterable) 会删除None 元素。现在我了解到它会删除所有虚假元素。
【解决方案2】:

为什么不嵌套推导式?

result = (x for x in (y.strip() for y in str_list) if len(x))

内部的() 生成了一个生成器,它只是str_list 中字符串的剥离版本。外部() 生成第二个生成器,它消耗第一个生成器并仅生成非空元素。您只遍历列表一次,并且只剥离每个字符串一次。

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 2013-03-06
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 2019-11-03
    • 2022-12-10
    • 2020-05-14
    相关资源
    最近更新 更多