Comment initialiser un tableau bidimensionnel en Python?


262

Je commence python et j'essaie d'utiliser une liste à deux dimensions, que je remplis initialement avec la même variable à chaque endroit. Je suis venu avec ceci:

def initialize_twodlist(foo):
    twod_list = []
    new = []
    for i in range (0, 10):
        for j in range (0, 10):
            new.append(foo)
        twod_list.append(new)
        new = []

Il donne le résultat souhaité, mais ressemble à une solution de contournement. Existe-t-il une manière plus simple / plus courte / plus élégante de procéder?


7
Juste un petit (ou important, selon qui regarde) nitpick: les listes ne sont pas des tableaux. Si vous voulez des tableaux, utilisez numpy.
Arnab Datta

Cette question est similaire : elle discute de l'initialisation des tableaux multidimensionnels en Python.
Anderson Green

@ArnabDatta Comment initialiseriez-vous un tableau multidimensionnel dans numpy, alors?
Anderson Green


Vous pouvez organiser les données dans une structure de type tableau en Python par défaut, mais ce n'est pas aussi efficace ou utile qu'un tableau NumPy. Surtout si vous souhaitez gérer de grands ensembles de données. Voici une documentation docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Réponses:


376

Un modèle qui est souvent apparu en Python était

bar = []
for item in some_iterable:
    bar.append(SOME EXPRESSION)

qui a contribué à motiver l'introduction de listes de compréhension, qui convertissent cet extrait en

bar = [SOME EXPRESSION for item in some_iterable]

ce qui est plus court et parfois plus clair. Habituellement, vous avez l'habitude de les reconnaître et de remplacer souvent les boucles par des compréhensions.

Votre code suit ce modèle deux fois

twod_list = []                                       \                      
for i in range (0, 10):                               \
    new = []                  \ can be replaced        } this too
    for j in range (0, 10):    } with a list          /
        new.append(foo)       / comprehension        /
    twod_list.append(new)                           /

35
Soit dit en passant, [[foo] * 10 pour x dans xrange (10)] peut être utilisé pour se débarrasser d'une compréhension. Le problème est que la multiplication fait une copie superficielle, donc new = [foo] * 10 new = [new] * 10 vous obtiendra une liste contenant la même liste dix fois.
Scott Wolchok

8
De même, [foo] * 10est une liste avec le même exact foo10 fois, ce qui peut ou non être important.
Mike Graham

2
nous pouvons utiliser la chose la plus simple: wtod_list = [[0 pour x dans xrange (10))] pour x dans xrange (10)]
indi60

2
Cela ne fait jamais de mal de montrer à quelqu'un à quoi ressemble un poisson.
Csteele5

2
Pour le commentaire de Mike Graham au sujet [foo] * 10: Cela veut dire que cela ne fonctionnera pas si vous remplissez un tableau avec des nombres aléatoires (évalue [random.randint(1,2)] * 10à [1] * 10ou [2] * 10qui signifie que vous obtenez un tableau de tous les 1 ou 2 s, au lieu d'un tableau aléatoire.
Tzu Li

226

Vous pouvez utiliser une liste de compréhension :

x = [[foo for i in range(10)] for j in range(10)]
# x is now a 10x10 array of 'foo' (which can depend on i and j if you want)

1
puisque la taille (10) est la même, c'est bien, sinon la boucle imbriquée doit venir en premier [foo for j in range (range_of_j)] for i in range (range_of_i)]
Dineshkumar

2
Cette réponse fonctionne bien, mais comme nous répétons les ilignes et les jcolonnes, je pense qu'il devrait être préférable de permuter iet jdans votre syntaxe pour une meilleure compréhension et changer la plage en 2 nombres différents.
DragonKnight

139

Ne l'utilisez pas [[v]*n]*n, c'est un piège!

>>> a = [[0]*3]*3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]

mais

    t = [ [0]*3 for i in range(3)]

fonctionne très bien.


26
oui, je suis aussi tombé dans ce piège. C'est parce que *copie addressl'objet (liste).
chinuy

1
Voté, car cela m'a eu. Pour être plus clair, [[0] * col for _ in range(row)].
Abhijit Sarkar

138

Cette méthode est plus rapide que les compréhensions de listes imbriquées

[x[:] for x in [[foo] * 10] * 10]    # for immutable foo!

Voici quelques timings python3, pour les petites et grandes listes

$python3 -m timeit '[x[:] for x in [[1] * 10] * 10]'
1000000 loops, best of 3: 1.55 usec per loop

$ python3 -m timeit '[[1 for i in range(10)] for j in range(10)]'
100000 loops, best of 3: 6.44 usec per loop

$ python3 -m timeit '[x[:] for x in [[1] * 1000] * 1000]'
100 loops, best of 3: 5.5 msec per loop

$ python3 -m timeit '[[1 for i in range(1000)] for j in range(1000)]'
10 loops, best of 3: 27 msec per loop

Explication:

[[foo]*10]*10crée une liste du même objet répétée 10 fois. Vous ne pouvez pas simplement l'utiliser, car la modification d'un élément modifiera ce même élément dans chaque ligne!

x[:]est équivalent list(X)mais est un peu plus efficace car il évite la recherche de nom. Quoi qu'il en soit, il crée une copie superficielle de chaque ligne, donc maintenant tous les éléments sont indépendants.

fooCependant, tous les éléments sont le même objet, donc s'il fooest modifiable , vous ne pouvez pas utiliser ce schéma., Vous devez utiliser

import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]

ou en supposant une classe (ou fonction) Fooqui renvoie foos

[[Foo() for x in range(10)] for y in range(10)]

4
@Mike, avez-vous manqué la partie en gras? si foo est mutable, aucune des autres réponses ici ne fonctionne (à moins que vous ne mutiez pas du tout foo)
John La Rooy

1
Vous ne pouvez pas copier correctement des objets arbitraires à l'aide de copy.deepcopy. Vous avez besoin d'un plan spécifique à vos données si vous avez un objet mutable arbitraire.
Mike Graham

1
Si vous avez vraiment besoin de vitesse dans une boucle, il est peut-être temps d'utiliser Cython, weave ou similaire ...
james.haggerty

1
@JohnLaRooy je pense que vous avez échangé xet y. Cela ne devrait-il pas être[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
user3085931

1
@Nils [foo]*10ne crée pas 10 objets différents - mais il est facile d'oublier la différence dans le cas où foo est immuable, comme un intou str.
John La Rooy

62

Pour initialiser un tableau bidimensionnel en Python:

a = [[0 for x in range(columns)] for y in range(rows)]

4
Pour initialiser toutes les valeurs à 0, utilisez simplement a = [[0 for x in range(columns)] for y in range(rows)].
ZX9

28
[[foo for x in xrange(10)] for y in xrange(10)]

1
xrange () a été supprimé dans python3.5
MiaeKim

pourquoi cela ne fonctionne pas: [0 * col] * ligne. Lorsque je modifie un élément, il se réplique à d'autres endroits. Mais je ne comprends pas pourquoi?
code muncher

Parce que cela fait exactement la même chose que le code de la question.
Ignacio Vazquez-Abrams

2
@codemuncher La raison pour laquelle vous [[0] * col] * rowne faites pas ce que vous voulez est que lorsque vous initialisez une liste 2D de cette façon, Python ne créera pas de copies distinctes de chaque ligne. Au lieu de cela, il lancera la liste externe avec des pointeurs vers la même copie de [0]*col. Toute modification que vous apportez à l'une des lignes sera alors reflétée dans les lignes restantes car elles pointent toutes vers les mêmes données en mémoire.
Addie

Juste une pensée mais toutes ces listes ne sont-elles pas bonnes à ajouter? C'est à dire. si je veux une liste 2D vide de dimension 3 * 6 et que je veux ajouter à l'index [0] [0], [1] [0], [2] [0] et ainsi de suite pour remplir les 18 éléments, aucun de ces réponses fonctionneront non?
mLstudent33

22

Habituellement, lorsque vous voulez des tableaux multidimensionnels, vous ne voulez pas une liste de listes, mais plutôt un tableau numpy ou éventuellement un dict.

Par exemple, avec numpy, vous feriez quelque chose comme

import numpy
a = numpy.empty((10, 10))
a.fill(foo)

2
Bien que ce numpysoit génial, je pense que cela pourrait être un peu exagéré pour un débutant.
Esteban Küber

3
numpy fournit un type de tableau multidimensionnel. Construire un bon tableau multidimensionnel à partir de listes est possible mais moins utile et plus difficile pour un débutant que d'utiliser numpy. Les listes imbriquées sont idéales pour certaines applications, mais ce n'est généralement pas ce que quelqu'un qui souhaite un tableau 2D serait le mieux.
Mike Graham

1
après quelques années à faire des applications python sérieuses, les bizarreries des tableaux python standard semblent justifier de continuer numpy. +1
javadba

12

Vous pouvez faire juste ceci:

[[element] * numcols] * numrows

Par exemple:

>>> [['a'] *3] * 2
[['a', 'a', 'a'], ['a', 'a', 'a']]

Mais cela a un effet secondaire indésirable:

>>> b = [['a']*3]*3
>>> b
[['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
>>> b[1][1]
'a'
>>> b[1][1] = 'b'
>>> b
[['a', 'b', 'a'], ['a', 'b', 'a'], ['a', 'b', 'a']]

11
D'après mon expérience, cet effet "indésirable" est souvent à l'origine de très mauvaises erreurs logiques. À mon avis, cette approche devrait être évitée, à la place, la réponse de @ Vipul est bien meilleure.
Alan Turing

cette approche fonctionne bien, pourquoi dans les commentaires certaines personnes la qualifient-elle de mauvaise?
Bravo

1
En raison de l'effet secondaire sous-désiré, vous ne pouvez pas vraiment le traiter comme une matrice. Si vous n'avez pas besoin de modifier le contenu, tout ira bien.
hithwen

9
twod_list = [[foo for _ in range(m)] for _ in range(n)]

pour n est le nombre de lignes, et m est le nombre de colonnes, et foo est la valeur.


8

S'il s'agit d'un tableau peu peuplé, il serait préférable d'utiliser un dictionnaire composé d'un tuple:

dict = {}
key = (a,b)
dict[key] = value
...

5
t = [ [0]*10 for i in [0]*10]

pour chaque élément un nouveau [0]*10sera créé.


4

Approche incorrecte: [[Aucun * m] * n]

>>> m, n = map(int, raw_input().split())
5 5
>>> x[0][0] = 34
>>> x
[[34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None]]
>>> id(x[0][0])
140416461589776
>>> id(x[3][0])
140416461589776

Avec cette approche, python ne permet pas de créer un espace d'adressage différent pour les colonnes externes et entraînera divers comportements inappropriés que vous attendez.

Approche correcte mais avec exception:

y = [[0 for i in range(m)] for j in range(n)]
>>> id(y[0][0]) == id(y[1][0])
False

C'est une bonne approche mais il y a une exception si vous définissez la valeur par défaut sur None

>>> r = [[None for i in range(5)] for j in range(5)]
>>> r
[[None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]
>>> id(r[0][0]) == id(r[2][0])
True

Définissez donc correctement votre valeur par défaut en utilisant cette approche.

Absolument correct:

Suivez la réponse du micro à double boucle .


3
Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")

1
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant pourquoi et / ou comment ce code répond à la question améliore sa valeur à long terme.
Ajean


3

utilisez la pensée la plus simple pour créer cela.

wtod_list = []

et ajoutez la taille:

wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

ou si nous voulons d'abord déclarer la taille. nous utilisons uniquement:

   wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

1

Comme l'ont souligné @Arnab et @Mike, un tableau n'est pas une liste. Peu de différences sont 1) les tableaux sont de taille fixe lors de l'initialisation 2) les tableaux prennent normalement en charge moins d'opérations qu'une liste.

Peut-être une surpuissance dans la plupart des cas, mais voici une implémentation de tableau 2D de base qui tire parti de l'implémentation de tableau matériel à l'aide de ctypes python (bibliothèques c)

import ctypes
class Array:
    def __init__(self,size,foo): #foo is the initial value
        self._size = size
        ArrayType = ctypes.py_object * size
        self._array = ArrayType()
        for i in range(size):
            self._array[i] = foo
    def __getitem__(self,index):
        return self._array[index]
    def __setitem__(self,index,value):
        self._array[index] = value
    def __len__(self):
        return self._size

class TwoDArray:
    def __init__(self,columns,rows,foo):
        self._2dArray = Array(rows,foo)
        for i in range(rows):
            self._2dArray[i] = Array(columns,foo)

    def numRows(self):
        return len(self._2dArray)
    def numCols(self):
        return len((self._2dArray)[0])
    def __getitem__(self,indexTuple):
        row = indexTuple[0]
        col = indexTuple[1]
        assert row >= 0 and row < self.numRows() \
               and col >=0 and col < self.numCols(),\
               "Array script out of range"
        return ((self._2dArray)[row])[col]

if(__name__ == "__main__"):
    twodArray = TwoDArray(4,5,5)#sample input
    print(twodArray[2,3])

1

La chose importante que j'ai comprise est: lors de l'initialisation d'un tableau (dans n'importe quelle dimension) Nous devons donner une valeur par défaut à toutes les positions du tableau. Ensuite, seule l'initialisation se termine. Après cela, nous pouvons changer ou recevoir de nouvelles valeurs à n'importe quelle position du tableau. Le code ci-dessous a parfaitement fonctionné pour moi

N=7
F=2

#INITIALIZATION of 7 x 2 array with deafult value as 0
ar=[[0]*F for x in range(N)]

#RECEIVING NEW VALUES TO THE INITIALIZED ARRAY
for i in range(N):
    for j in range(F):
        ar[i][j]=int(input())
print(ar)

1

Si vous utilisez numpy , vous pouvez facilement créer des tableaux 2D :

import numpy as np

row = 3
col = 5
num = 10
x = np.full((row, col), num)

X

array([[10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10]])

1
row=5
col=5
[[x]*col for x in [b for b in range(row)]]

Ce qui précède vous donnera un tableau 2D 5x5

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

Il utilise la compréhension de liste imbriquée. Répartition comme ci-dessous:

[[x]*col for x in [b for b in range(row)]]

[x] * col -> expression finale évaluée
pour x in -> x sera la valeur fournie par l'itérateur
[b pour b dans la plage (ligne)]] -> Itérateur.

[b pour b dans la plage (ligne)]] ceci évaluera à [0,1,2,3,4] puisque ligne = 5
alors maintenant il se simplifie pour

[[x]*col for x in [0,1,2,3,4]]

Cela évaluera à [[0] * 5 pour x dans [0,1,2,3,4]] -> avec x = 0 1ère itération
[[1] * 5 pour x dans [0,1,2, 3,4]] -> avec x = 1 2e itération
[[2] * 5 pour x dans [0,1,2,3,4]] -> avec x = 2 3e itération
[[3] * 5 pour x dans [0,1,2,3,4]] -> avec x = 3 4ème itération
[[4] * 5 pour x dans [0,1,2,3,4]] -> avec x = 4 5ème itération


0

C'est le meilleur que j'ai trouvé pour enseigner aux nouveaux programmeurs, et sans utiliser de bibliothèques supplémentaires. J'aimerais quelque chose de mieux cependant.

def initialize_twodlist(value):
    list=[]
    for row in range(10):
        list.append([value]*10)
    return list

0

Voici un moyen plus simple:

import numpy as np
twoD = np.array([[]*m]*n)

Pour initialiser toutes les cellules avec une valeur 'x', utilisez:

twoD = np.array([[x]*m]*n

0

J'utilise souvent cette approche pour initialiser un tableau à 2 dimensions

n=[[int(x) for x in input().split()] for i in range(int(input())]


0

Le modèle général pour ajouter des dimensions pourrait être tiré de cette série:

x = 0
mat1 = []
for i in range(3):
    mat1.append(x)
    x+=1
print(mat1)


x=0
mat2 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp.append(x)
        x+=1
    mat2.append(tmp)

print(mat2)


x=0
mat3 = []
for i in range(3):
    tmp = []
    for j in range(4):
        tmp2 = []
        for k in range(5):
            tmp2.append(x)
            x+=1
        tmp.append(tmp2)
    mat3.append(tmp)

print(mat3)

Bienvenue chez SO. Cette question a déjà une réponse acceptée massivement votée. À première vue, ce message ne répond pas vraiment à la question. Voir stackoverflow.com/help/how-to-answer pour des conseils.
Nick

0

Vous pouvez essayer ceci [[0] * 10] * 10. Cela renverra le tableau 2D de 10 lignes et 10 colonnes avec la valeur 0 pour chaque cellule.


Ceci est essentiellement la même réponse que stackoverflow.com/a/25601284/2413201 ...
Armali

2
Cela crée un tableau de 10 pointeurs sur la même ligne. Si vous le faites a = [[0]*10]*10et que a[0][0] = 1vous verrez alors le premier élément de chaque ligne maintenant égal à 1
andnik

0

lst = [[0] * m pour i dans la plage (n)]

initialiser toutes les matrices n = lignes et m = colonnes


Pouvez-vous formater le code en tant que code? Ce serait beaucoup plus lisible.
Thomas

0

Une autre façon consiste à utiliser un dictionnaire pour contenir un tableau à deux dimensions.

twoD = {}
twoD[0,0] = 0
print(twoD[0,0]) # ===> prints 0

Cela peut simplement contenir n'importe quelle valeur 1D, 2D et pour l'initialiser à 0ou toute autre valeur int, utilisez des collections .

import collections
twoD = collections.defaultdict(int)
print(twoD[0,0]) # ==> prints 0
twoD[1,1] = 1
print(twoD[1,1]) # ==> prints 1

0

Code:

num_rows, num_cols = 4, 2
initial_val = 0
matrix = [[initial_val] * num_cols for _ in range(num_rows)]
print(matrix) 
# [[0, 0], [0, 0], [0, 0], [0, 0]]

initial_val doit être immuable.


-3
from random import randint
l = []

for i in range(10):
    k=[]
    for j in range(10):
        a= randint(1,100)
        k.append(a)

    l.append(k)




print(l)
print(max(l[2]))

b = []
for i in range(10):
    a = l[i][5]
    b.append(a)

print(min(b))

4
Veuillez ajouter du texte décrivant ce que fait votre code.
whackamadoodle3000

1
Habituellement, il vaut mieux expliquer une solution au lieu de simplement publier quelques lignes de code anonyme. Vous pouvez lire Comment écrire une bonne réponse , et aussi Expliquer les réponses entièrement basées sur du code .
Massimiliano Kraus
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.