Lesson 9
Listes bidimensionnelles (tableaux)
1. Listes imbriquées: traitement et impression
Dans le monde réel Souvent, les tâches doivent stocker une table de données rectangulaire. [Dites-en plus à ce sujet!] De telles tables sont appelées matrices ou tableaux bidimensionnels. En Python, n'importe quelle table peut être représentée comme une liste de listes (une liste, où chaque élément est à son tour une liste). Par exemple, voici le programme qui crée un tableau numérique avec deux lignes et trois colonnes, puis fait quelques manipulations avec celui-ci:a = [[1, 2, 3], [4, 5, 6]] print(a[0]) print(a[1]) b = a[0] print(b) print(a[0][2]) a[0][1] = 7 print(a) print(b) b[2] = 9 print(a[0]) print(b)
Le premier élément d' a
ici - a[0]
- est une liste de nombres [1, 2, 3]
. Le premier élément de cette nouvelle liste est a[0][0] == 1
; de plus, a[0][1] == 2
, a[0][2] == 3
, a[1][0] == 4
, a[1][1] == 5
, a[1][2] == 6
.
Pour traiter un tableau à deux dimensions, vous utilisez généralement des boucles imbriquées. La première boucle parcourt le numéro de ligne, la seconde boucle parcourt les éléments à l'intérieur d'une rangée. Par exemple, c'est ainsi que vous affichez la liste numérique bidimensionnelle sur l'écran ligne par ligne, en séparant les nombres par des espaces:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] for i in range(len(a)): for j in range(len(a[i])): print(a[i][j], end=' ') print()
Nous avons déjà essayé d'expliquer qu'une variable de for-loop en Python peut itérer non seulement sur un range()
, mais généralement sur tous les éléments de n'importe quelle séquence. Les séquences en Python sont des listes et des chaînes (et d'autres objets que nous n'avons pas encore rencontrés). Regardez comment vous pouvez imprimer un tableau à deux dimensions, en utilisant cette fonctionnalité pratique de la boucle for
:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] for row in a: for elem in row: print(elem, end=' ') print()
Naturellement, pour sortir une seule ligne, vous pouvez utiliser la méthode join()
:
for row in a: print(' '.join([str(elem) for elem in row]))
C'est ainsi que vous pouvez utiliser 2 boucles imbriquées pour calculer la somme de tous les nombres de la liste à 2 dimensions:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] s = 0 for i in range(len(a)): for j in range(len(a[i])): s += a[i][j] print(s)
Ou la même chose avec itération par les éléments, pas par les variables i
et j
:
a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]] s = 0 for row in a: for elem in row: s += elem print(s)
2. Listes imbriquées: création
Supposons que deux nombres soient donnés: le nombre de rangées de n
et le nombre de colonnes m
. Vous devez créer une liste de taille n
× m
, remplie, disons, de zéros.
La solution évidente semble être fausse:
a = [[0] * m] * n
Cela peut être facilement vu si vous définissez la valeur d' a[0][0]
à 5
, puis imprimez la valeur d' a[1][0]
- il sera également égal à 5. La raison en est, [0] * m
retourne juste une référence à une liste de m
zéros, mais pas une liste. La répétition subséquente de cet élément crée une liste de n
éléments qui font tous référence à la même liste (tout comme l'opération b = a
pour les listes ne crée pas la nouvelle liste), toutes les lignes de la liste résultante sont donc identiques chaîne.
En utilisant notre visualiseur, gardez une trace de l'identifiant des listes. Si deux listes ont le même numéro d'identification, c'est en fait la même liste en mémoire.
n = 3 m = 4 a = [[0] * m] * n a[0][0] = 5 print(a[1][0])
Ainsi, une liste bidimensionnelle ne peut pas être créée simplement en répétant une chaîne. Que faire?..
Une manière possible: vous pouvez créer une liste de n
éléments (disons, de n
zéros) et ensuite faire de chacun des éléments un lien vers une autre liste unidimensionnelle de m
éléments:
n = 3 m = 4 a = [0] * n for i in range(n): a[i] = [0] * m
Une autre façon (mais similaire): créer une liste vide et y append
un nouvel élément n
fois (cet élément devrait être une liste de longueur m
):
n = 3 m = 4 a = [] for i in range(n): a.append([0] * m)
Mais le plus simple est d'utiliser générateur, en créant une liste de n
éléments, dont chacun est une liste de m
zéros:
n = 3 m = 4 a = [[0] * m for i in range(n)]
Dans ce cas, chaque élément est créé indépendamment des autres. La liste [0] * m
est n
fois conscrite comme la nouvelle, et aucune copie des références ne se produit.
3. Comment entrez-vous un tableau à deux dimensions?
Par exemple, un programme prend en entrée un tableau à deux dimensions sous la forme de n
lignes, chacune contenant m
nombres séparés par des espaces. Comment forcez-vous le programme à le lire? Un exemple de comment vous pouvez le faire:
# la première ligne d'entrée est le nombre de lignes du tableau n = int(input()) a = [] for i in range(n): a.append([int(j) for j in input().split()])
Ou, sans utiliser d'appels imbriqués sophistiqués:
# la première ligne d'entrée est le nombre de lignes du tableau n = int(input()) a = [] for i in range(n): row = input().split() for i in range(len(row)): row[i] = int(row[i]) a.append(row)
Vous pouvez faire la même chose avec les générateurs:
# la première ligne d'entrée est le nombre de lignes du tableau n = int(input()) a = [[int(j) for j in input().split()] for i in range(n)]
4. Traitement d'un tableau à deux dimensions: un exemple
Supposons qu'on vous donne un tableau carré (un tableau de n
lignes et n
colonnes). Et supposons que vous devez définir des éléments de la diagonale principale égaux à 1 (c'est-à-dire les éléments a[i][j]
pour lesquels i==j
), pour définir des éléments supérieurs à cette diagonale égale à 0, et pour définir des éléments en dessous de cette diagonale égale à 2. Autrement dit, vous devez produire un tel tableau (exemple pour n==4
):
1 0 0 0 2 1 0 0 2 2 1 0 2 2 2 1(Dans ce cas, vous pouvez le faire manuellement en définissant
a[0][0] = 1
, a[0][1] = 0
et ainsi de suite, mais vous ne le faites pas manuellement pour les tableaux de 100 lignes et 100 colonnes , ce qui est souvent le cas.) Nous sommes impatients de vous montrer plusieurs façons de résoudre ce problème. Tout d'abord, notez que les éléments qui se trouvent au-dessus de la diagonale principale sont des éléments a[i][j]
pour lesquels i<j
, et que pour les éléments en dessous de la diagonale principale i>j
. Ainsi, nous pouvons comparer les valeurs i
et j
, qui déterminent la valeur de a[i][j]
. Nous obtenons l'algorithme suivant:
n = 4 a = [[0] * n for i in range(n)] for i in range(n): for j in range(n): if i < j: a[i][j] = 0 elif i > j: a[i][j] = 2 else: a[i][j] = 1 for row in a: print(' '.join([str(elem) for elem in row]))
Cet algorithme est lent: il utilise deux boucles et pour chaque paire (i,j)
exécute une ou deux if
instructions. Si nous compliquons l'algorithme, nous serons en mesure de le faire sans condition.
D'abord, remplissez la diagonale principale, pour laquelle nous aurons besoin d'une boucle:
for i in range(n): a[i][i] = 1
Remplissez ensuite avec des zéros tous les éléments au-dessus de la diagonale principale. Pour cela, pour chaque ligne avec le nombre i
vous devez assigner une valeur à a[i][j]
pour j
= i+1
, ..., n-1
. Pour ce faire, vous avez besoin de boucles imbriquées:
for i in range(n): for j in range(i + 1, n): a[i][j] = 0
Par analogie, pour j
= 0
, ..., i-1
met les éléments a[i][j]
égal à 2
:
for i in range(n): for j in range(0, i): a[i][j] = 2
Vous pouvez combiner tout ce code et recevoir une autre solution:
n = 4 a = [[0] * n for i in range(n)] for i in range(n): for j in range(0, i): a[i][j] = 2 a[i][i] = 1 for j in range(i + 1, n): a[i][j] = 0 for row in a: print(' '.join([str(elem) for elem in row]))
Voici une autre solution, qui répète les listes pour construire les lignes suivantes de la liste. La i
-th ligne de la liste est composée de i
nombres 2
, suivis d'un entier 1
, suivi de ni-1
zéros:
n = 4 a = [0] * n for i in range(n): a[i] = [2] * i + [1] + [0] * (n - i - 1) for row in a: print(' '.join([str(elem) for elem in row]))
Comme d'habitude, vous pouvez remplacer la boucle avec le générateur:
n = 4 a = [0] * n a = [[2] * i + [1] + [0] * (n - i - 1) for i in range(n)] for row in a: print(' '.join([str(elem) for elem in row]))
5. Tableaux bidimensionnels: générateurs imbriqués
Vous pouvez utiliser des générateurs imbriqués pour créer des tableaux bidimensionnels, en plaçant le générateur de la liste qui est une chaîne, à l'intérieur du générateur de toutes les chaînes. Rappelez-vous que vous pouvez créer une liste de n
lignes et m
colonnes en utilisant le générateur (qui crée une liste de n
éléments, où chaque élément est une liste de m
zéros):
[[0] * m for i in range(n)]
Mais la liste interne peut également être créée en utilisant, par exemple, un tel générateur: [0 for j in range(m)]
. Nesting un générateur dans un autre, nous obtenons
[[0 for j in range(m)] for i in range(n)]
Comment est-ce lié à notre problème? La chose est, si le nombre 0 est remplacé par une expression qui dépend de i
(le numéro de ligne) et j
(le numéro de colonne), vous obtenez la matrice remplie selon une formule.
Par exemple, supposons que vous ayez besoin d'initialiser le tableau suivant (par commodité, des espaces supplémentaires sont ajoutés entre les éléments):
0 0 0 0 0 0 0 1 2 3 4 5 0 2 4 6 8 10 0 3 6 9 12 15 0 4 8 12 16 20
Dans ce tableau, il y a n = 5
lignes, m = 6
colonnes, et l'élément avec l'indice de ligne i
et l'index de colonne j
est calculé par la formule a[i][j] = i * j
.
Comme toujours, vous pouvez utiliser un générateur pour créer un tel tableau:
[[i * j for j in range(m)] for i in range(n)]