【问题标题】:Are Python list comprehensions the same thing as map/grep in Perl?Python 列表理解是否与 Perl 中的 map/grep 相同?
【发布时间】:2010-11-27 23:34:19
【问题描述】:

我在理解 Python 中的列表解析语法时遇到了一些麻烦,因此我开始思考如何在我更熟悉的 Perl 中实现相同的功能。我意识到基本示例(取自this page)都可以在Perl 中使用mapgrep 完成。

例如

(python)                            (perl)                  
S = [x**2 for x in range(10)]       @S = map { $_**2 } ( 0..9 );
V = [2**i for i in range(13)]       @V = map { 2**$_ } ( 0..12 );
M = [x for x in S if x % 2 == 0]    @M = grep { $_ % 2 == 0 } @S;

那么“列表理解”只是“映射和/或过滤列表”的一个花哨术语,还是有更多含义?

【问题讨论】:

    标签: python perl list


    【解决方案1】:

    列表推导式也使事情变得平坦:

    例如:

    [(x, y) for x in xrange(10) if x%2 == 0 for y in xrange(20) if x!=y]

    如果您在此处使用嵌套映射,则还必须使用 concat(对列表求和)。

    【讨论】:

      【解决方案2】:

      它们是用于映射和过滤序列的“pythonic”版本,但它们允许做一些其他事情,例如展平(固定级别)嵌套列表,例如:

      [j for i in nested_list for j in i]
      

      使用常规 map 和 lambda 表达式不能做的另一件事是在结构上分解迭代值,例如:

      [(x%y)*z for x,y,z in list_with_triplets_of_ints]
      

      当然有一些解决方法,例如:

      aux = lambda x,y,z: (x%y)*z
      map(lambda t: aux(*t), list_with_triplets_of_ints)
      

      但是当您需要应用的转换已经定义时,通常使用映射会更简单,例如:

      map(int, list_of_str_values)
      

      而不是

      [int(i) for i in list_of_str_values]
      

      【讨论】:

      • +1 谢谢。我特别喜欢三连音的例子;这很难用 map 简洁地做到。
      【解决方案3】:

      你是对的:列表推导本质上只是 map 和 filter 的语法糖(来自函数式编程世界的术语)。

      希望这个示例代码能证明它们的相等性:

      >>> # Python 2
      >>> [x**2 for x in range(10)] == map(lambda x: x**2, range(10))
      True
      >>> [2**i for i in range(13)] == map(lambda x: 2**x, range(13))
      True
      >>> S = [x**2 for x in range(10)]
      >>> [x for x in S if x % 2 == 0] == filter(lambda x: x % 2 == 0, S)
      True
      

      请注意,这仅在 Python 2.X 中有效,正如 SilentGhost 在评论中指出的那样。为了使其与 Python 3 兼容,您必须将调用 map 或 filter 封装在 list 构造函数中,因为 map 和 filter 已更新为返回迭代器,而不是列表。

      >>> # Python 3
      >>> [x**2 for x in range(10)] == list(map(lambda x: x**2, range(10)))
      True
      >>> [2**i for i in range(13)] == list(map(lambda x: 2**x, range(13)))
      True
      >>> S = [x**2 for x in range(10)]
      >>> [x for x in S if x % 2 == 0] == list(filter(lambda x: x % 2 == 0, S))
      True
      

      【讨论】:

        【解决方案4】:

        是的。 Python 语法的强大之处在于,相同的语法(在圆括号内而不是方括号内)也用于定义生成器,生成器按需生成值序列。

        【讨论】:

          【解决方案5】:

          是的,它们基本相同。

          其实Python也有map函数:

          S = map(lambda x: x**2, range(10))
          

          与上面的第一个示例相同。但是,列表推导式语法在 Python 中是非常受欢迎的。我相信 Guido 曾被引述说他对引入函数式语法感到遗憾。

          然而,真正有趣的地方在于列表推导的下一个演变,即生成器。这些允许您返回一个迭代器 - 而不是一次处理整个列表,它执行一次迭代然后返回,因此您不必同时将整个列表保存在内存中。非常强大。

          【讨论】:

          • 我认为生成器本质上就是其他语言所说的迭代器?
          • @friedo 迭代器是一种模式,生成器是实现该模式的一种方式
          【解决方案6】:

          列表推导比映射或过滤器更强大,因为它们允许您抽象地使用列表。

          当您的地图进一步嵌套更多地图和过滤器调用时,使用它们也更方便。

          【讨论】:

          • 你能举个例子说明“抽象地玩列表”是什么意思吗?
          猜你喜欢
          • 2016-07-23
          • 2011-03-24
          • 2013-06-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-29
          • 2021-10-06
          • 2018-01-25
          相关资源
          最近更新 更多