Python: Liste

From Wiki Cours
Revision as of 11:22, 7 November 2016 by Wiki-cours (talk | contribs) (→‎Tableaux multidimensionnels)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

<--Sommaire

Initialisation

Une liste est un tableau ordonné qui contient des pointeurs vers des objets qui peuvent être simplement des données numériques (entiers ou réels) ou des choses plus compliquées comme des nombres complexes ou même des listes. Pour créer une liste vide, on peut faire

a = list()
a = []
print(a) # affiche la liste

On peut définir une liste en explicitant son contenu, les éléments sont alors séparés par des virgules. Voici un exemple de liste au contenu homogène puis un avec un contenu

a = [1,4,2,3] # une liste d'entiers
a = [ 2, complex(1,3), 4.5, ['a','b','c'] ] # une liste au contenu inhomogène

Indexage

On accède aux éléments de la liste à l'aide de l'opérateur d'indiçage [] comme en C. De même qu'en C, le premier indice est 0. Cet opérateur permet à la fois d'accéder au contenu stocké à la ième place, via a[i], mais aussi de le modifier.

a = [3,2,1,0]
print(a[0],a[1],a[2],a[3])
a[0] = 'a'
print(a)

À cet usage proche des langages de bas niveaux, Python offre des fonctions puissantes de 'slicing' (découpage) des indices qui permettent d'accéder facilement à un ou des éléments en particulier. Voici quelques exemples à essayer qui permettent de comprendre les mécanismes

a = list(range(10)) # listes des entiers de 0 à 9
              # en Python 2, la fonction range() renvoie une liste, pas besoin de mettre list()
              # en Python 3, elle renvoie un itérateur à partir duquel on crée une liste avec list()
a[-1]         # dernier élément du tableau, 
              # a[-i] équivaut à a[len(a)-i] sauf pour i=0
a[2:]         # affiche tous les éléments à partir du 2ème
a[:5]         # affiche tous les éléments jusqu'au 5ème
a[start:stop] # affiche tous les éléments d'indices entre start et (stop-1)
a[start:stop:step] # affiche tous les éléments d'indices entre start et (stop-1) par saut de 'step'
a[1:10:2]     # les entiers impaires
# et vous pouvez jouer en combinant les astuces...
a[-9:-2:3]
# attention cependant, on pourrait croire que l'on peut mettre à zéro
# tout ou partie des éléments d'une liste avec les commandes
a[:] = 0
a[0:10:2] = 0
# mais cela n'est pas possible car les membres de gauche sont dans ce cas des listes
# la solution est alors de parcourir la liste ou bien d'affecter une autre liste membre à membre
a[0:10:2] = [0.0]*len(a[0:10:2])

Copie d'une liste

Il faut faire attention au fait qu'en Python, qui a un typage dynamique, l'affection suivante fait que la liste b va pointer vers le contenu de a:

a = [3,2,1,0]
b = a

Si l'on modifie un élément de b, le contenu est changé et donc les éléments de a également

a = [3,2,1,0]
b = a
b[2] = 5
print(a,b)

Pour réellement créer une copie indépendante, il faut générer une nouvelle liste en dupliquant le contenu de a. Il y a deux façons simple de le faire: avec l'initialisateur list() ou l'indiçage du contenu en entier via l'opération [:]

a = [3,2,1,0]
b = list(a)
b[2] = 5
c = a[:]
c[1] = -3
print(a,b,c)

En fait, il reste cependant un problème dans le cas où la liste contient des éléments qui sont des objets plus compliqués que les types de base (entiers, réels,...), en particulier des listes. Regardons en effet le résultat d'une copie d'une liste de listes:

a = [ [2,3] for i in range(4) ]
b = list(a)
b[2][0] = 5
print(a,b)

On voit que le contenu de a a été modifié car la copie a copié comme nouvel élément de b l'adresse de la liste élément de a. Pour effectuer une copie complète du contenu à tous les niveaux, Python offre une fonction deepcopy présente dans la bibliothèque copy du standard. Refaire alors

from copy import deepcopy
a = [ [2,3] for i in range(4) ]
b = deepcopy(a)
b[2][0] = 5
print(a,b)

Noter que cette bibliothèque offre également une fonction copy qui fait la même chose qu'avec list() mais avec un nom plus évocatif et il s'agit surtout d'une méthode plus générique et ré-définissable pour des objets plus complexes.

from copy import copy
a = [ [2,3] for i in range(4) ]
b = copy(a)
...

Génération de listes

Un des points forts de Python est la possibilité de générer et modifier efficacement des listes. Vous pouvez étudier les exemples suivants

N = 5
# addition de liste '+', rajoute un élément ou fusionne deux listes (l'ordre compte)
print([1,2] + [3,4,5],  [3,4,5] + [1,2])
# opérateur multiplier '*' répète N fois l'addition:
print( [1]*N )
# vous pouvez combiner ces opérations pour obtenir des structures complexes dès l'initialisation
print( ([ [2,3] ]*2 + ['a'])*3 )

# On peut ajouter un élément avec l'addition ou bien la méthode '''append()'''
a = [ 0 ]*4
a += [1]  # ne pas oublier les crochets ici car il faut ajouter une liste de 1 élément.
a.append(1) # plus efficace, l'argument de append étant l'élément à ajouter, pas de crochets ici.

# utilisation de la fonction range().
# range(n) : itérateur sur les entiers depuis 0 jusqu'à n-1
# range(start,stop,step) : parcourt l'intervalle [start,stop-1] par saut de step
print(list(range(10)))
print(list(range(-10,10,2)))

Méthodes utiles pour les listes

# nombre d'éléments
len(a)

# Ajout d'un élément 'e' à la fin de la liste.
# plus efficace que l'addition de liste
a.append(e)

# Insertion de l'élément 'e' à l'indice 'ind'. Si l'indice est supérieur à 
# la taille de la liste, l'élément est mis à la fin
a.insert(ind,e)

# Destruction du ième élément, ou même d'une série correspondant
# à un découpage des indices
del a[i]
del a[2:5]  # détruit les éléments d'indices 2 à 4

# Elimination de l'élément 'e' en le recherchant à partir de la fin 
# (message d'erreur si l'élément n'est pas dans la liste)
a.remove(e)
a.remove(a[-1]) # enlève le dernier élément
a.remove(a[0])  # enlève le premier élément sauf s'il apparaît plus tard dans la liste

# Elimination de l'élément d'indice 'ind' et renvoie de la valeur enlevée. 
# En l'absence de 'ind', le dernier élément est enlevé.
a.pop(ind)
print(a.pop(), a)

# Indice d'un élément 'e' sur le domaine d'indices [start,stop].
# Retourne l'indice du premier élément rencontré en partant de la gauche. 
# Par défaut, start est 0 et stop est le dernier indice
a.index(e,start,stop)

# Inversion de l'ordre des éléments
a.reverse()

# tri de la liste (message d'erreur si les éléments ne sont pas comparables)
a.sort()
print(sorted(a))

# comptage du nombre d’occurrence de l'élément 'e' à l'intérieur de la liste
a.count(e)

Parcourir une liste

Il existe plusieurs façon plus ou moins concise et intuitive de parcourir une liste, par des procédés qui sont parfois communs à d'autres conteneurs.

# la solution la plus courante en utilisant range() et len() pour générer la liste des indices
for i in range(len(a)):
    a[i] = 0.0

# on peut générer une liste d'indices pour ne travailler que sur 
# une partie des éléments
indices_pairs = range(len(a))[0:len(a):2]
for i in indices_pairs:
    a[i] = 0.0

# on peut aussi utiliser directement un pointeur sur les éléments de a
# mais on ne pourra dans ce cas pas modifier le contenu de l'élément,
# seulement y accéder en lecture
for e in a:
    print(e) # on peut utiliser l'information dans e pour faire un calcul
    e = 0.0
print(a) # n'a pas été modifiée

# enfin, on peut extraire à la fois le couple (tuple) indice/élément
# en utiliser la fonction enumerate()

for index,elem in enumerate(a):
    print(index, elem)

Quelques fonction utiles

La fonction est évidente si aucune précision n'est donnée

a = [1,4,6,2,3,10]
max(a)
min(a)
sum(a)
map(f,a) # applique la fonction f() aux éléments de a
         # map() en Python 3 renvoie un itérateur
list(map(f,a)) # pour créer une liste contenant f(a)
filter(test,a) # renvoie un itérateur dont les éléments retournent True si
               # la fonction test(t) leur est appliquée, rien sinon
               # rajouter list(...) si vous voulez créer une liste
list(filter(lambda x: x%2,a))     # renvoie les  nombres impairs
list(filter(lambda x: not x%2,a)) # renvoie les  nombres pairs

for i in zip(range(10),range(10,20)): # permet de parcourir des listes en parallèle
    print(i)                          # renvoie un tuple sur les éléments de même indice
                                      # on peut passer plus de deux listes en argument
                                      # zip(a,b,c,d,...)

Tableaux multidimensionnels

Il est relativement facile de créer des tableaux multidimensionnels avec des listes de listes:

mat = [ [1,2,3], [3,2,1], [1,1,2] ]
mat[0][1]  # accès aux éléments i,j

On prendra garde que les méthodes de slicing ne sont pas toujours intuitives dans la syntaxe. À l'usage, on préfèrera l'utilisation de librairies d'algèbre linéaire comme numpy et les objets type ndarray.

De plus, l'initialisation avec l'opérateur * pour les listes n'a pas un comportement intuitif, préférer les initialisations avec la compréhension des listes. Regarder par exemple :

L = 3

m = [ [0]*L ]*L  # utilise une copie multiple de la meme liste                                                                                                                                                                                 
for i in range(L):
    for j in range(L):
        m[i][j] = i+j
print(m)

m = [ [0 for i in range(L)] for j in range(L) ]
for i in range(L):
    for j in range(L):
        m[i][j] = i+j
print(m)

m = list()
for i in range(L):
    m.append([ i+j  for j in range(L)])
print(m)