2 votes

Bizarrerie de Python impliquant map et reduce

Désolé pour le titre vague, mais je n'ai vraiment aucune idée de ce qui se passe ici.

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)

Sortie souhaitée :

___
___
___

Production réelle :

__
__
__

Et quand je change la finale else en strxo a return str(n) au lieu de return "_" J'ai compris :

000
000
000

Ce qui est ce que j'attendais et la forme que je veux, mais je veux remplacer ces zéros. Quelle est la cause de ce problème ?

0 votes

Je ne comprends pas comment vous espérez obtenir 5 caractères de soulignement en appelant une fonction trois fois. Ou pourquoi la sortie souhaitée est 5x3 en premier lieu alors qu'en même temps une grille 3x3 de 0s est la forme souhaitée.

2 votes

Première étape du débogage : Réécrivez votre code pour qu'il soit lisible. Idéalement, débarrassez-vous de ce style fonctionnel en utilisant reduce et utiliser des compréhensions de listes à la place. Mais au moins, divisez cette monstruosité en plusieurs lignes.

4 votes

Aussi, pourquoi faites-vous cela avec map y reduce en premier lieu ? Votre extérieur reduce est simplement moins efficace et plus difficile à comprendre '\n'.join , votre list(map(lambda…)) est une compréhension de liste moins efficace et plus difficile à comprendre, et votre intérieur reduce Je ne suis pas sûr de ce qu'il est censé faire ; pourquoi appelez-vous le service de l'immigration ? strxo sur la valeur accumulée ici ? Et pourquoi tout cela doit-il être une ligne monstrueuse, au lieu d'être divisé en petits morceaux que vous pouvez comprendre et déboguer vous-même ?

6voto

juanpa.arrivillaga Points 35811

Le problème est que votre fonction de réduction la plus interne, celle qui agit sur vos sous-listes, transforme toujours le deuxième argument en _ :

lambda a, b: strxo(a) + strxo(b)

Donc, sur le dernier élément de cette réduction, b es __ qui se transforme en _ !

Vous voulez carte strxo sur tout d'abord, et ensuite réduire en utilisant la concaténation.

Donc vous voulez quelque chose comme ça :

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

Note, j'ai supprimé l'appel inutile à list .

Mais plus important encore, arrêter d'utiliser reduce et l'opérateur de concaténation pour joindre des chaînes de caractères !

Elle est inutilement verbeuse et inefficace (sa complexité en temps est quadratique).

Au lieu de cela, utilisez :

joinstr = ''.join

Ce qui est une fonction parfaitement adaptée. La programmation fonctionnelle ne signifie pas "utiliser map et reduce partout où c'est possible".

Donc, voici de la bonne programmation fonctionnelle :

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

def board_str(board):
    return join_newline(map(lambda l: joinstr(map(strxo,l)), board))

Mieux encore, vous devriez simplement utiliser compréhensions de listes qui sont éminemment les constructions fonctionnelles (Python les a volées à Haskell, entre autres). Il est souvent plus facile à lire que map + lambda :

def board_string(board):
    return join_newline([joinstr(map(strxo, l)) for l in board])

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X