Python怪异涉及map和reduce

Wil*_*sco 2 python arrays functional-programming python-3.x off-by-one

对于模糊的标题很抱歉,但我真的不知道这里发生了什么.

from functools import reduce

arr = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

def strxo(n):
    if (n == -1):
        return "X"
    elif (n == 1):
        return "O"
    else:
        return "_"

def prboard(board):
    print(reduce(lambda x, y: x + "\n" + y, list(map(lambda l: reduce(lambda a, b: strxo(a) + strxo(b), l), board))))

prboard(arr)
Run Code Online (Sandbox Code Playgroud)

期望的输出:

___
___
___
Run Code Online (Sandbox Code Playgroud)

实际输出:

__
__
__
Run Code Online (Sandbox Code Playgroud)

当我改变决赛elsestrxo,return str(n)而不是return "_"我得到:

000
000
000
Run Code Online (Sandbox Code Playgroud)

这是我期望的和我想要的形状,但我想替换那些零.是什么造成的?

jua*_*aga 6

问题是你最内在的减少函数,即作用于你的子列表的函数,总是将第二个参数转换为_:

lambda a, b: strxo(a) + strxo(b)
Run Code Online (Sandbox Code Playgroud)

所以,在减少的最后一个元素b__,它变成了_!

您希望首先映射 strxo到所有内容,然后使用连接减少.

所以你想要这样的东西:

reduce(lambda x, y: x + "\n" + y, map(lambda l: reduce(lambda a, b: a + b, map(strxo, l)), board))
Run Code Online (Sandbox Code Playgroud)

请注意,我删除了不必要的电话list.

但更重要的是,停止使用reduce和连接运算符来连接字符串!

它不必要地冗长,并且启动效率低(它将具有二次时间复杂度).

相反,使用:

joinstr = ''.join
Run Code Online (Sandbox Code Playgroud)

这是一个非常好的功能.功能编程并不意味着"使用地图并尽可能减少地图".

所以,这是一些很好的函数式编程:

joinstr = ''.join
join_newline = '\n'.join

def board_str(board):
    return join_newline(map(lambda l: joinstr(map(strxo,l)), board))
Run Code Online (Sandbox Code Playgroud)

更好的是,你应该只使用列表推导,这是非常实用的构造(Python从Haskell,btw中窃取它们).它通常比map+ 更具可读性lambda:

def board_string(board):
    return join_newline([joinstr(map(strxo, l)) for l in board])
Run Code Online (Sandbox Code Playgroud)

  • @Aran-Fey这是因为如果容器已经是列表或元组,那么实现中有一个"快速路径",否则,无论如何它都会调用它上面的列表! (2认同)
  • @ Aran-Fey实际上,`join`的原因是列表更快(在CPython中)`join`只是把你给它的任何东西除了`list`或`tuple`变成`list`,所以它可以直接迭代list-or-tuple内部存储阵列.并且`[...]`比`list(...)`更快(不像3.x早期那样多,但仍然显着,但由于愚蠢的语义边缘情况,其中一部分是不可消除的). (2认同)