2 votes

Python générant une liste avec des éléments lexicaux uniques

Supposons que je veuille créer un tableau vide 3x4 2d comme ceci.

x = [[0.0]*3]*4

Cependant, en utilisant le code ci-dessus,

print x[0] is x[1]     # Output = True

C'est-à-dire,

x[1][1] = 5.0
print x      # Output = [[0.0, 5.0, 0.0], 
             #           [0.0, 5.0, 0.0], 
             #           [0.0, 5.0, 0.0], 
             #           [0.0, 5.0, 0.0]]

Pour éviter de créer cette liste avec 4 références identiques à la même liste, j'ai fait des choses comme :

y = [[0.0]*3, [0.0]*3, [0.0]*3, [0.0]*3]

print y[0] is y[1]     # Output = False
y[1][1] = 5.0
print y      # Output = [[0.0, 0.0, 0.0], 
             #           [0.0, 5.0, 0.0], 
             #           [0.0, 0.0, 0.0], 
             #           [0.0, 0.0, 0.0]]

Une autre approche consisterait à utiliser la compréhension des listes.

z = [[0.0]*3 for x in range(4)]

mais, ça semble toujours un peu laid.

Existe-t-il un moyen de rendre le tableau 'y' ou 'z' où toutes les références sont uniques dans un format élégant comme dans 'x' en utilisant multiplier sur une liste ?

4voto

user2357112 Points 37737

La compréhension des listes est la réponse habituelle. Elle n'est pas aussi propre que la multiplication de séquences, mais c'est ce qu'il y a de mieux :

[[0.0]*3 for _ in xrange(4)]

Notez que pour un grand nombre d'applications où vous voulez une grille de valeurs, vous faites quelque chose qui numpy ndarrays pourrait faire plus rapidement et plus proprement.

3voto

abarnert Points 94246

Cela figure dans la FAQ officielle de la programmation Python, sous la forme suivante Comment créer une liste multidimensionnelle ? .

La FAQ suggère trois possibilités :

  1. Créez une liste de la longueur souhaitée, puis remplacez chaque élément dans une boucle.
  2. Utilisez une liste de compréhension.
  3. Utilisez quelque chose comme un numpy.array au lieu d'une liste multidimensionnelle en premier lieu.

Je pense que la plupart des développeurs Python les suggéreraient dans l'ordre exactement inverse de celui de la FAQ mais personne ne se plaindrait d'aucune d'entre elles. Donc :

a = np.zeros((3, 4))

a = [[0.0]*3 for _ in range(4)]

a = [None] * 4
for i, _ in enumerate(a):
    a[i] = [0.0]*3

Si vous vous retrouvez à faire cela souvent (et que vous n'utilisez pas numpy), vous pouvez toujours l'intégrer dans une fonction. En fait, il s'agit généralement de la meilleure façon de traiter les fonctions tout ce qui est c'est moche même si on le fait de la manière la plus pythonique possible. Donc :

def make_matrix(r, c):
    return [[0.0]*c for _ in range(r)]

Et ensuite c'est aussi clair que possible :

a = make_matrix(3, 4)

itertools a une fonction appelée repeat ce qui équivaut à la version iteratrice de * . Les documents montrent un code équivalent en Python pur, il est donc assez facile de l'adapter pour copier (superficiellement ou en profondeur) l'objet pour chaque représentant :

def repeat(obj, times):
    for _ in range(times):
        yield copy.copy(obj)

list(repeat([0.0]*3, 4))

Je ne pense pas que ce soit plus lisible - surtout si vous voulez l'utiliser à plusieurs niveaux :

list(repeat(list(repeat(0.0, 3)), 4))

même si vous l'intégrez dans une fonction qui l'explique pour vous :

def srepeat(object, times):
    return list(repeat(object, times))
srepeat(srepeat(0.0, 3), 4)

et si vous l'intégrez dans une fonction qui gère de multiples dimensions, vous venez de recréer la fonction make_matrix .

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