web-dev-qa-db-fra.com

Itération à travers le tableau

J'ai un tableau de bools et maintenant je veux échanger ces entrées contre des nombres.

False => 0
True => 1

J'ai écrit deux morceaux de code différents et j'aimerais savoir lequel est le meilleur et pourquoi. Il ne s'agit pas tant de résoudre réellement le problème que d'apprendre.

arr = [[True,False],[False,True],[True,True]]

for i,row in enumerate(arr):
    for j,entry in enumerate(row):
        if entry:
            arr[i][j] = 1
        else:
            arr[i][j] = 0
print(arr)

Et la deuxième approche:

arr = [[True,False],[False,True],[True,True]]

for i in range(len(arr)):
    for j in range(len(arr[i])):
        if arr[i][j]:
            arr[i][j] = 1
        else:
            arr[i][j] = 0    
print(arr)

J'ai lu qu'il existe des moyens de le faire avec l'importation de itertools ou similaire. Je ne suis vraiment pas fan d'importer des choses si cela peut être fait avec des "outils embarqués", mais devrais-je plutôt les utiliser pour ce problème?

8
Swift

Définissons votre tableau:

>>> arr = [[True,False],[False,True],[True,True]]

Maintenant, convertissons les booléens en entier:

>>> [[int(i) for i in row] for row in arr]
[[1, 0], [0, 1], [1, 1]]

Alternativement, si nous voulons être plus flexibles sur ce qui est remplacé, nous pouvons utiliser une déclaration ternaire:

>>> [[1 if i else 0 for i in row] for row in arr]
[[1, 0], [0, 1], [1, 1]]
12
John1024

Si vous souhaitez conserver une boucle for (par exemple parce que vous voulez muter le tableau existant au lieu d'en créer un nouveau), vous devez simplifier le code.

Je simplifierais d'abord la boucle externe en supprimant l'indexation (ce n'est pas nécessaire car il est encore plus facile de modifier une ligne qu'un tableau imbriqué):

for row in arr:
    for j, entry in enumerate(row):
        if entry:
            row[j] = 1
        else:
            row[j] = 0

ces types d'instructions if simples peuvent souvent être simplifiés en utilisant une expression if:

 row[j] = 1 if entry else 0

mais dans ce cas, nous pouvons faire encore mieux. bool est une sous-classe de int (c'est-à-dire que tous les bool sont des int), et True et False sont définis pour être exactement 1 et 0 respectivement - si vous faites défiler jusqu'à la section des spécifications du PEP 285 ( https://www.python.org/dev/peps/ pep-0285 / ) vous verrez que cette équivalence n'est pas accidentelle, mais beaucoup par conception.

Nous pouvons donc utiliser le constructeur int pour récupérer les valeurs entières sous-jacentes [*], puisque int(True) == 1 et int(False) == 0, l'expression if peut être simplifiée pour:

row[j] = int(entry)

[*] techniquement, il s'agit d'une conversion ascendante explicite vers une classe de base, et non un constructeur de conversion.

Le code simplifié:

for row in arr:
    for j, entry in enumerate(row):
        row[j] = int(entry)
4
thebjorn