函数式编程与列表理解

2024-09-27 21:34:56 发布

您现在位置:Python中文网/ 问答频道 /正文

Mark Lutz在《学习Python》一书中举了一个例子:

>>> [(x,y) for x in range(5) if x%2==0 for y in range(5) if y%2==1]
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
>>>

过了一会儿,他说“映射和过滤器等价物”是可能的,尽管复杂和嵌套。在

最接近我的结论是:

^{pr2}$

元组的顺序不同,必须引入嵌套列表。我很好奇什么是等效的。在


Tags: in过滤器列表forif顺序range例子
3条回答

要附加到@Kasramvd's explanation的注释。在

可读性在Python中很重要。这是语言的特点之一。许多人会认为列表理解是唯一可读的方式。在

然而,有时,尤其是当你在处理多个条件迭代时,将你的标准与逻辑分开会更清楚。在这种情况下,可以优选使用函数方法。在

from itertools import product

def even_and_odd(vals):
    return (vals[0] % 2 == 0) and (vals[1] %2 == 1)

n = range(5)

res = list(filter(even_and_odd, product(n, n)))

需要注意的一点是,嵌套列表的理解是O(n2)顺序。意思是它在两个范围的乘积上循环。如果要使用mapfilter,则必须创建所有组合。你可以在过滤之后或之前做这些,但是不管你做什么,你都不可能拥有这两个函数的所有这些组合,除非你改变范围和/或修改其他东西。在

一种完全实用的方法是使用itertools.product()和{},如下所示:

In [16]: from itertools import product

In [17]: list(filter(lambda x: x[0]%2==0 and x[1]%2==1, product(range(5), range(5))))
Out[17]: [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]

还请注意,使用两次迭代的嵌套列表理解基本上比多个map/filter函数更具可读性。当你的函数仅仅是内置函数时,使用内置函数的性能要比列表理解快得多,这样你就可以确保它们都是在C级别上执行的。当你用一个lambda函数这样的Python/higher lever操作来打破这个链,你的代码不会比列表理解快。在

我认为表达式[(x, y) for x in range(5) if x % 2 == 0 for y in range(5) if y % 2 == 1]中唯一令人困惑的部分是隐藏了一个隐式flatten操作。在

让我们先考虑一下表达式的简化版本:

def even(x):
    return x % 2 == 0

def odd(x):
    return not even(x)

c = map(lambda x: map(lambda y: [x, y], 
                      filter(odd, range(5))), 
        filter(even, range(5)))

print(c)
# i.e. for each even X we have a list of odd Ys:
# [
#   [[0, 1], [0, 3]],
#   [[2, 1], [2, 3]],
#   [[4, 1], [4, 3]]
# ]

然而,我们需要的是完全相同但扁平化的列表[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]。在

official python docs我们可以得到flatten函数的示例:

^{pr2}$

它基本上相当于以下列表理解表达式:

flattened = [x for sublist in c for x in sublist]
print(flattened)

# ... which is basically an equivalent to:
# result = []
# for sublist in c:
#   for x in sublist:
#     result.append(x)

相关问题 更多 >

    热门问题