【问题标题】:How to set local variable in list comprehension?如何在列表理解中设置局部变量?
【发布时间】:2014-12-27 15:32:01
【问题描述】:

我有一个方法,它接受一个列表并返回一个对象:

# input a list, returns an object
def map_to_obj(lst):
    a_list = f(lst)
    return a_list[0] if a_list else None

我想获得一个列表,其中包含所有不是None 的映射元素。

像这样:

v_list = [v1, v2, v3, v4]

[map_to_obj(v) for v in v_list if map_to_obj(v)]

但是在列表推导中两次调用map_to_obj 方法似乎不太好。

有没有办法在列表推导中使用局部变量,以便获得更好的性能?

还是编译器会自动优化?

这就是我想要的:

(sml like)
[let mapped = map_to_obj(v) in for v in v_list if mapped end] 

【问题讨论】:

    标签: python list-comprehension


    【解决方案1】:

    使用嵌套列表推导:

    [x for x in [map_to_obj(v) for v in v_list] if x]

    或者更好的是,围绕生成器表达式的列表推导:

    [x for x in (map_to_obj(v) for v in v_list) if x]

    【讨论】:

    • 这是一个很好的答案,当然它与behzad 的答案相同,用列表推导代替mapfilter...我要投票正如我喜欢 Lying Dog 如何用 lc 翻译 filter 一样,但 OP 可能会批准其中一个答案,因为它们都是很好、有用的答案。
    • 内部理解应该是生成器表达式。无需构建整个列表,然后才丢弃空项目以构建另一个列表。
    • @Lying Imho Tim 的建议是合理且有意义的,请考虑编辑您的答案以反映他的建议。
    • @cowbert:如果涉及lambda(实际上是任何 Python 实现的函数,理解可以内联以避免调用开销),是的,listcomp 获胜。 map/filter 如果回调函数是 C 内置函数,则可以获胜,因为它们可以将所有工作推送到 C 层,绕过字节码解释器开销,这是 listcomps 无法避免的,因为它们是 Python 级函数, 只是对附加到列表步骤的直接字节码支持。
    • 愚蠢的例子:改变 behzad 的答案,用 None.__ne__ 替换 lambda t: t is not None,而它的工作方式却有点奇怪(它返回 False 其他 Nones 和 @ 987654335@,这恰好是真实的,对于其他一切),将提高该解决方案的速度(在本地测试中,filter 工作下降了近 2 倍),但以可理解性为代价。
    【解决方案2】:

    Python 3.8 开始,并引入assignment expressions (PEP 572):= 运算符),可以在列表解析中使用局部变量以避免调用两次相同的函数:

    在我们的例子中,我们可以将map_to_obj(v) 的求值命名为变量o,同时使用表达式的结果来过滤列表;因此使用o 作为映射值:

    [o for v in [v1, v2, v3, v4] if (o := map_to_obj(v))]
    

    【讨论】:

      【解决方案3】:

      变量赋值只是一个单一的绑定:

      [x   for v in l   for x in [v]]
      

      这是一个更一般的答案,也更接近您的建议。 所以对于你的问题,你可以写:

      [x   for v in v_list   for x in [map_to_obj(v)]   if x]
      

      【讨论】:

      • 这与我的答案的不同之处仅在于使用 1 元素列表而不是 1 元素元组,我认为当不需要可变时,元组胜过列表。 :-)
      【解决方案4】:

      使用python内置filter可以避免重新计算:

      list(filter(lambda t: t is not None, map(map_to_obj, v_list)))
      

      【讨论】:

      • 有没有一次迭代的解决方案?
      • @HaoTan 不在 python 3 中;在 python 3 中,map 返回一个映射对象而不是一个列表,filter 返回一个过滤对象;因此,这将链接函数而不创建中间列表。
      • 是否可以使用reduce 来完成这项工作?
      • @HaoTan:你为什么会这样? reduce 是将很多东西组合成一个东西,而不是把很多东西变成很多东西。配对的mapfilter(即listified)完成的工作相当于执行过滤和映射操作的listcomp 完成的工作。
      【解决方案5】:

      可以在理解中设置局部变量,方法是稍微作弊并使用额外的“for”“迭代”包含局部变量所需值的 1 元素元组。这是使用这种方法解决 OP 问题的方法:

      [o for v in v_list for o in (map_to_obj(v),) if o]
      

      这里,o 是每个 v 设置为等于 map_to_obj(v) 的局部变量。

      在我的测试中,这比 Lying Dog 的嵌套生成器表达式略快(并且也比 OP 对 map_to_obj(v) 的双重调用快,令人惊讶的是,如果 map_to_obj 函数是'不要太慢)。

      【讨论】:

        【解决方案6】:

        列表推导适用于简单的情况,但有时一个普通的旧 for 循环是最简单的解决方案:

        other_list = []
        for v in v_list:
            obj = map_to_obj(v)
            if obj:
                other_list.append(obj)
        

        现在如果你真的想要一个列表组合并且不想构建一个 tmp 列表,你可以使用 filtermap 的迭代器版本:

        import itertools as it
        result = list(it.ifilter(None, it.imap(map_to_obj, v_list)))
        

        或更简单地说:

        import itertools as it
        result = filter(None, it.imap(map_to_obj, v_list)))
        

        迭代器版本不构建临时列表,它们使用惰性求值。

        【讨论】:

          【解决方案7】:

          我想出了一个使用reduce的方法:

          def map_and_append(lst, v):
              mapped = map_to_obj(v)
              if mapped is not None:
                  lst.append(mapped)
              return lst
          
          reduce(map_and_append, v_list, [])
          

          这个性能怎么样?

          【讨论】:

          • 您可以使用 timeit 模块来计时不同的解决方案,但是您上面的 sn-p 是做一件非常简单的事情的任意过度复杂的方法 - 我怀疑它会更快或更比普通的 for 循环或 filter/imap 解决方案更节省空间......
          • @Bruno 我喜欢你的«overcomplexificated»!
          • 如果我看一下没有 itertools 的答案,尽管性能,我敢说Lying Dog's one 是最能表达意图的,因此也是最易读的。那么性能呢?好吧,我不知道您在 f(lst) 调用中花费了多少 CPU,但以一种或另一种方式删除 Nones 不太可能改变整个情况。
          • reduce 真的不需要在这里。它用于将值列表减少为单个值(通常是标量列表为单个标量),而不是将一个列表转换为另一个列表。
          猜你喜欢
          • 1970-01-01
          • 2013-08-02
          • 1970-01-01
          • 2022-01-07
          • 2019-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多