Mark Lutz'最清晰的解决方案短期"锻炼犯罪的疯狂" - 生成偶数/奇数对(元组)

时间:2017-07-10 05:04:47

标签: python list-comprehension

我正在仔细研究Mark Lutz' Learning Python, 5th Edition。在第20章(关于理解)中,Mark将内置函数(mapfilter)与语法理解进行了比较。

例如,他比较

[x ** 2 for x in range(10)]

list(map((lambda x: x ** 2), range(10)))

...产生[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]的相同结果(第一个通过理解,第二个通过map)。

然后,他仅以理解形式给出了第二个例子:

  

[以下]表达式将0到4之间的偶数与0到4之间的奇数组合。if子句在每次迭代中过滤掉项目:

[(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)]。)

但Mark确实 使用map / filter写出相同的功能,而不是给读者留下这个多汁的挑战:

  

这个最后一个例子的地图和过滤器相当复杂并且深度嵌套,所以我甚至不会尝试在这里展示它。我将把它的编码留作禅宗大师,前Lisp程序员和犯罪疯子的练习!

(这里的例子是一个很好的例子,以突出map和理解之间的差异,这在许多其他情况下似乎非常相似,但在这种情况下在句法复杂性方面非常不同。)

我决定接受挑战,并根据mapfilter来实现这种理解。我在下面提供了答案。

我的问题是,使用mapfilter实现上述理解的方式是什么(可以说是最干净,最清晰,即使是丑陋的)?

3 个答案:

答案 0 :(得分:2)

这是另一种方法(为便于阅读而格式化):

list(filter(
    lambda pair: pair[0] % 2 == 0 and pair[1] % 2 == 1,
    reduce(
        lambda a, b: a+b,
        list(map(
            lambda x:
                list(map(
                    lambda y: (x, y),
                    range(5)
                )),
            range(5)
        ))
    )
))

(对于Python 3,假设您已完成from functools import reduce。在Python 2中,它稍微简单一些,因为可以删除对list的所有调用。)

很多复杂性来自于必须仅使用map / reduce来生成范围的笛卡尔积,这非常麻烦。如果您允许使用itertools,事情会变得更加简单:

list(filter(
    lambda pair: pair[0] % 2 == 0 and pair[1] % 2 == 1,
    itertools.product(range(5), repeat=2)
))

答案 1 :(得分:1)

这是我最好的选择(似乎reduce,以及lambda,是必要的)(如果在Python而不是lambdas中绑定是可能的,我没有&t; t得到了本书的那一部分):

result = reduce(lambda r, g: r.extend(g) or r, 
            list(map(lambda x: 
                    list(map(lambda y: (x, y), 
                        filter(lambda a: a % 2 == 1, range(5)))),
                filter(lambda b: b % 2 == 0, range(5)))),
            [])

答案 2 :(得分:0)

这是解决方案:

f = map(lambda x: 
        list(map(lambda y: 
            (x, y), filter(lambda h: 
                h % 2 == 1, range(5))
            )
        ), 
        filter(lambda g: g % 2 == 0, range(5))
    )

print(list(f))

这是结果:

[[(0, 1), (0, 3)], [(2, 1), (2, 3)], [(4, 1), (4, 3)]]

注意:结果列表包括两个两次调用的双重括号。而且,如果两个双括号使您感到不安,则始终可以使用for循环跳过它。