Aller au contenu

Types séquences : str, tuple, list

Chapitre en cours de relecture

Ce chapitre manque quelques exercices et corrections mineures. Vous pouvez vous y attaquer, mais il faudra y revenir plus tard quand les exercices auront étés ajoutés.

Ce chapitre est également trop détaillé, il doit subir une réécriture.

Un des intérêt des ordinateurs est d'automatiser le traitement de données multiples, voir massives. Par exemple, appliquer un filtre sur les milliers d'images qui composent une vidéo, traiter les requêtes de centaines d'utilisateurs, ou encore analyser des Go de données provenant d'instruments de mesure scientifique.

Pour le moment, on n'a stocké que des "valeurs isolées" dans les variables.

Quand on fait

a = 1

a contient un seul entier. Celà permet déjà de faire de nombreux programmes, mais on est quand même relativement limités.

Le premier problème est sémantique : si l'on voulait représenter un vecteur en deux dimensions, \((x,y)\), on devrait utiliser deux variables :

# vec = (1,2)
vec_x = 1
vec_y = 2

Celà peut vite rendre le code difficile à lire et à faire évoluer.

Ici, puisque les deux coordonnées d'un vecteur vont ensemble, on aimerait pouvoir les grouper dans un même variable, quelque chose comme :

vec_x = (1,2)

Le second problème est pratique : on ne sait pas toujours à l'avance combien d'éléments on va manipuler. Si on voulait écrire un programme travaillant sur les millions de pixels qui composent une image, il serait déraisonnable d'écrire un programme qui déclare une variable par pixel :

pixel0 = #...
pixel1 = #...
#...

Tous les langages de programmation fournissent une manière de manipuler des données multiples et complexes. En général, celà passe par des types construits.

Idée de types construits

Un type construit est un type de données qui est composé d'autre types de données.

Par exemple, un vecteur en 2D est composé de deux nombres, pour ses deux coordonnées, autrement dit, c'est un couple ou une paire de nombres. Ca pourrait donner quelque chose comme :

Vecteur 2D -> paire : int * int

ou encore :

Vecteur 2D -> paire : float * float

Ici paire est un type construit, une paire de nombres. Le * représente une association, pas une multiplication !

Le nom et le prénom d'un individu pourrait aussi être groupés dans une paire de chaînes :

Nom complet -> paire : string * string

Dans ce chapitre, on va aborder des types construits que l'on appelle les séquences. Ce sont des types qui ont pour objectif de stocker des données dans un ordre déterminé. En voici trois :

TODO (prof) ajouter schéma ici

  • str (chaîne de caractères), une séquence de caractères.
  • tuple (n-uplet), une séquence de valeurs de types arbitraires.
  • list (liste ou tableau), une séquence de valeurs de types arbitraires.

Ces trois types séquences supportent globalement les mêmes opérations, on va donc les présenter en même temps. A noter qu'en informatique, une liste et un tableau ne sont pas exactement la même chose. Pour ne pas créer de confusion, on va donc utiliser list pour désigner le type Python correspondant. De la même manière, on utilisera tuple pour désigner le type correspondant.

Construction

str

Pour construire une valeur de type chaîne, on écrit des caractères encadrés par des doubles ou des simples quotes:

s1 = "unechaine"
s2 = 'uneautrechaine'

On peut construire une chaîne vide en n'écrivant aucun caractère entre les quotes:

v1 = ""
v2 = ''

list

Pour construire une valeur de type list, on spécifie des valeurs encadrées par des crochets [], et séparées par des virgules.

une_list = [1, 2, 3, 4]
print(une_list)

affiche

[1, 2, 3, 4]

On peut aussi utiliser la fonction list, qui permet de construire une list à partir d'un type séquence :

une_list = list("abcdef")
print(une_list)

affiche

['a', 'b',  'c', 'd', 'e', 'f']

On peut construire une list vide en écrivant des parenthèses sans rien au milieu :

list_vide = []
print(list_vide)

affiche

[]

tuple

La construction d'un tuple est très similaire à celle d'une list, on utilise des parenthèses () à la place des crochets [].

Pour construire une valeur de type tuple, on spécifie des valeurs encadrées par des parenthèses (), et séparées par des virgules.

un_tuple = (1, 2, 3, 4)
print(un_tuple)

affiche

(1, 2, 3, 4)

On peut aussi utiliser la fonction tuple, qui permet de construire un tuple à partir d'un type séquence :

un_tuple = tuple("abcdef")
print(un_tuple)

affiche

('a', 'b',  'c', 'd', 'e', 'f')

On peut construire un tuple vide en écrivant des parenthèses sans rien au milieu :

tuple_vide = ()
print(tuple_vide)

affiche

()

Attention, si on veut construire un tuple ne contenant qu'une seule valeur, il faut rajouter une virgule après celle-ci :

tuple_une = (1,)
print(tuple_une)

affiche

(1,)

Longueur d'une séquence

La fonction len (pour LENgth, longueur en anglais) permet de connaître le nombre de valeurs contenues dans un type séquence.

s = "abcdef"
longueur = len(s)
print(longueur)

affiche

6
t = (0,1,2,3,4,5)
longueur = len(t)
print(longueur)

affiche

6
l = [0,1,2,3,4,5]
longueur = len(l)
print(longueur)

affiche

6

Accès par indice : opérateur []

On peut accéder à un élément donné par sa position, appelée indice (ou parfois index comme en anglais), dans un type séquence en utilisant l'opérateur [], avec la syntaxe suivante :

s[i]

s est la valeur de type séquence et i l'indice de l'élément auquel on veut accéder.

Attention

Le premier élément d'une séquence est à l'indice 0 !

s = "abcdef"
premier = s[0]
second = s[1]
print(premier)
print(second)

affiche

a
b

remarque : l'élément d'une chaîne en python, le caractère, est aussi une chaîne, de longueur 1.

t = (10,11,12,13,14,15)
premier = t[0]
second = t[1]
print(premier)
print(second)

affiche

10
11
l = [10,11,12,13,14,15]
premier = l[0]
second = l[1]
print(premier)
print(second)

affiche

10
11

Si l'indice i donné est négatif, alors la position est comptée à partir de 1 en partant de la fin de la séquence s (ou plutôt, la position accédée est len(s) + i) :

s = "abcdef"
dernier = s[-1]
avant_dernier = s[-2]
print(dernier)
print(avant_dernier)

affiche

f
e
t = (10,11,12,13,14,15)
dernier = s[-1]
avant_dernier = s[-2]
print(dernier)
print(avant_dernier)

affiche

15
14
l = [10,11,12,13,14,15]
dernier = s[-1]
avant_dernier = s[-2]
print(dernier)
print(avant_dernier)

affiche

15
14

Pour une séquence s, l'indice i donné doit vérifier l'encadrement -len(s) <= i < len(s), sans quoi une erreur est levée pendant l'opération.

s = "abcdef"
trop_loin = s[6]

Génère une erreur indice hors limite (index out of range). Ici, i == len(s), donc i < len(s) n'est pas vérifiée.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
t = (10,11,12,13,14,15)
trop_loin = t[-7]

Génère une erreur indice hors limite (index out of range). Ici, i == - len(t) - 1, donc -len(s) <= i n'est pas vérifiée.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range
l = [10,11,12,13,14,15]
trop_loin = l[100]

Génère une erreur indice hors limite (index out of range). Ici, i < len(l) n'est pas vérifiée.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

Exercice : afficher le premier charactère d'une chaine

Implantez une fonction qui prends en entrée une chaîne de caractère non vide et retourne son premier charactère.

def premier_caractere(s):
    """ s une chaîne, s != ""
    affiche le premier caractère de s

    premier_caractère("abc") vaut "a"
    """
    pass
  • Utilisez l'opérateur [].
  • Les caractères dans une chaine comm
def premier_caractere(s):
    """ s une chaîne, s != ""
    affiche le premier caractère de s

    premier_caractere("abc") vaut a
    """
    return s[0]

Exercice : i-ème caractère d'une chaîne

Implantez la fonction suivante :

def ieme_caractere(s, i):
    """s une chaine, i un entier, i > 0
    retourne le i-ème caractère de s

    ieme_charactere("abc", 2) vaut "c"
    """
    pass
  • Utilisez [i] pour accéder au caractère en position i dans une chaine.
def ieme_caractere(s, i):
    """s une chaine, i un entier, i > 0
    retourne le i-ème caractère de s

    ieme_charactere("abc", 2) vaut "c"
    """
    return s[i]

Appelez la fonction de la manière suivante :

ieme_charactere("abc", 8)

Ce code produit une erreur. Essayez de comprendre pourquoi.

  • La dernière ligne d'une erreur Python est généralement la meilleure pour comprendre l'erreur.
  • index veut dire indice. C'est un synomyme de position dans notre cas.
  • out of range veut dire hors de portée

Index out of range veut dire que l'on essaye d'accéder à une position qui n'est pas dans la chaîne.

Ici, notre chaîne comporte 3 caractères. Comme les indices commencent à zéro, la position la plus grande dans une chaîne de 3 caractères est 2. Donc, quand on essaie d'accéder à la position 8, cette position n'existe pas dans la chaîne, ce qui génère une erreur.

Changez la spécification et ajoutez une assertion pour tenir compte de ce prérequis : la position doit être strictement inférieure à la longueur de la chaîne.

La longueur d'une chaîne se s'obtient avec la fonction len, qui prends la chaîne en paramètre. len("abc") vaut 3.

def ieme_caractere(s, i):
    """s une chaine, i un entier, i > 0, i < len(s)
    retourne le i-ème caractère de s

    ieme_charactere("abc", 2) vaut "c"
    """
    assert i < len(s)

    return s[i]

Les accès en dehors des positions sont une source fréquente d'erreurs en programmation, il faut donc garder cette possibilité en tête pour débugger plus vite !

Exercice : premier élément d'un tuple

Implantez une fonction qui prends en entier un tuple non vide et retourne son premier élément :

def premier_element(t):
    """t un tuple non vide
    retourne le premier élément de t

    Exemple :
    premier_element((10, 20, 30)) retourne 10
    """
    pass

utilisez l'opérateur []

def premier_element(t):
    """t un tuple non vide
    retourne le premier élément de t

    Exemple :
    premier_element((10, 20, 30)) retourne 10
    """
    assert t != () ##on vérifie que le tuple est non vide
    return t[0]

Exercice : i-ème élément d'un tuple

Implantez une fonction qui retourne le i-eme élément d'un tuple :

def ieme_element(t, i):
    """t un tuple, len(t) > i
    i un entier, i >= 0
    retourne l'élement de t en position i

    Exemple :
    ieme_element((10, 20, 30, 40), 2) retourne 30 
    """
    pass

Utilisez [i] pour accéder à l'éléménet en position i dans un tuple

def ieme_element(t, i):
    """t un tuple, len(t) > i
    i un entier, i >= 0
    retourne l'élement de t en position i

    Exemple :
    ieme_element((10, 20, 30, 40), 2) retourne 30 
    """
    assert i >= 0
    assert len(t) > i
    return t[i]

Exercice : premier élément d'une list

Implantez une fonction qui prends en entier une list non vide et retourne son premier élément :

def premier_element(l):
    """l une list non vide
    retourne le premier élément de l

    Exemple :
    premier_element([10, 20, 30]) retourne 10
    """
    pass

utilisez l'opérateur []

def premier_element(l):
    """l un tuple non vide
    retourne le premier élément de l

    Exemple :
    premier_element([10, 20, 30]) retourne 10
    """
    assert l != () ##on vérifie que le tuple est non vide
    return l[0]

Exercice : i-ème élément d'une list

Implantez une fonction qui retourne le i-eme élément d'une list :

def ieme_element(l, i):
    """l un tuple, len(l) > i
    i un entier, i >= 0
    retourne l'élement de l en position i

    Exemple :
    ieme_element([10, 20, 30, 40], 2) retourne 30 
    """
    pass

Utilisez [i] pour accéder à l'éléménet en position i dans une list

def ieme_element(t, i):
    """l un tuple, len(l) > i
    i un entier, i >= 0
    retourne l'élement de t en position i

    Exemple :
    ieme_element((10, 20, 30, 40), 2) retourne 30 
    """
    assert i >= 0
    assert len(l) > i
    return l[i]

Itération while

En connaissant la longueur d'une séquence et en pouvant accéder à ses éléments un par un, on peut utiliser une boucle while pour faire une opération sur chaque élément. C'est ce qu'on appele parcourir la séquence.

s = "chaine"
i = 0 ## On commence à la position (indice) 0
while i < len(s): ## Tant qu'on a pas dépassé la fin
    print(s[i]) ## On fait notre opération
    i = i + 1 ## puis on rajoute 1 à la position

affiche :

c
h
a
i
n
e
t = (1, 2, 3, 4, 5)
i = 0 ## On commence à la position (indice) 0
while i < len(t): ## Tant qu'on a pas dépassé la fin 
    print(t[i]) ## On fait notre opération
    i = i + 1 ## puis on rajoute 1 à la position

affiche :

1
2
3
4
5
l = [1, 2, 3, 4, 5]
i = 0 ## On commence à la position (indice) 0
while i < len(l): ## Tant qu'on a pas dépassé la fin 
    print(l[i]) ## On fait notre opération
    i = i + 1 ## puis on rajoute 1 à la position

affiche :

1
2
3
4
5

Exercice : tableau d'itération

Observez le code suivant :

s = "chaiiiine"
i = 0
r = ""
while i < 5:
    r = r + s[i]
    i = i + 1
print(r)

Dressez un tableau qui à chaque ligne récapitule les valeurs de r et i à chaque fois que la condition de la boucle est testée.

Voici le début du tableau

i r
0 ""
1 "c"
2 "ch"
i r commentaire
0 "" Ici on rentre dans la boucle
1 "c" Premier tour
2 "ch"
3 "cha"
4 "chai"
5 "chain" Ici on sort de la boucle

TODO (prof) ajouter exercices pour tuple et list

Itération for in

Souvent, on n'est pas intéressé par les indices, et on veut seulement parcourir tous les éléments d'une séquence. Dans ce cas là, on peut utiliser une boucle for in, que l'on pourrait traduire par pour chaque dans. Pour une séquence s, la syntaxe est la suivante :

for e in s:
    # operations

Ici e pourrait avoir un autre nom : c'est une variable qui représente successivement chaque élément de la séquence, dans l'ordre croissant de leurs indices. On lit : pour chaque e dans s.

On peut alors réécrire le code de la section précédente plus simplement :

s = "chaine"
for c in s ## pour chaque c (caractère) dans s
    print(c)

affiche :

c
h
a
i
n
e
t = (1, 2, 3, 4, 5)
for e in t: ## pour chaque e (élément) dans t 
    print(e) 

affiche :

1
2
3
4
5
l = [1, 2, 3, 4, 5]
for e in l: ## pour chaque e (élément) dans l
    print(e)

affiche :

1
2
3
4
5

Exercice : inverser une chaîne

Ecrivez une fonction inverse, qui prends en paramètre une chaîne, et retourne une chaîne avec les caractères en ordre inverse

def inverse(s):
    """ s une chaine
    retourne une chaine contenant les caractères de s en ordre inverse

    inverse("abcdef") vaut "fedcba"
    """
    pass

Observez la fonction suivante et adaptez-là :

def copie(s):
    """ s une chaine
    retourne une copie de s

    copie("abcdef") vaut "abcdef"
    """
    cop = ""
    ## pour chaque caractère dans la chaine d'origine
    for c in s:
        cop = cop + c ## on l'ajoute à la FIN de la copie 
    return cop

N'hesitez pas à faire un tableau d'itération pour mieux comprendre cette fonction.

def inverse(s):
    """ s une chaine
    retourne une chaine contenant les caractères de s en ordre inverse

    inverse("abcdef") vaut "fedcba"
    """
    inv = ""
    ## pour chaque caractère dans la chaine d'origine
    for c in s:
        inv = c + inv ## on l'ajoute à au DEBUT de la copie inverse
    return inv

Exercice : somme d'un tuple

Implantez la fonction suivante :

def somme(t):
    """t un tuple non vide ne contenant que des entiers
    retourne la somme des éléments de t

    Exemple:
    somme((1,2,3,4,5)) = 15
    """
    pass

Utilisez une boucle for. Il vous faudra aussi utiliser une variable supplémentaire, initialisée à 0.

def somme(t):
    """t un tuple non vide ne contenant que des entiers
    retourne la somme des éléments de t

    Exemple:
    somme((1,2,3,4,5)) = 15
    """
    s = 0
    for e in t:
        s = s + e
    return s

Exercice : moyenne d'une list

Implantez la fonction suivante :

def moy(l):
    """l une list non vide ne contenant que des entiers
    retourne la moyenne des éléments de l

    Exemple:
    moy([1,2,3,4,5]) retourne 3
    """
    pass

Utilisez une boucle for.

Rappel : la moyenne d'une séquence d'éléments est la somme des élements divisés par le nombre d'éléments.

def moy(l):
    """l une list non vide ne contenant que des entiers
    retourne la moyenne des éléments de l

    Exemple:
    moy([1,2,3,4,5]) retourne 3
    """
    somme = 0
    for e in l:
        somme = somme + e
    return somme / len(l)

Concaténation : opérateur +

L'opérateur + permet de concaténer deux séquences de même type. Nous l'avons déjà vu pour le type str.

s1 = "1234"
s2 = "6789"
s = s1 + s2
print(s)
affiche

12346789
t1 = (1,2,3,4)
t2 = (6,7,8,9)
t = t1 + t2
print(t)

affiche

(1, 2, 3, 4, 6, 7, 8, 9)
l1 = [1, 2, 3, 4]
l2 = [6, 7, 8, 9]
l = l1 + l2
print(l)

affiche

[1, 2, 3, 4, 6, 7, 8, 9]

TODO (prof) ajouter exos ici

Duplicats

Les str, tuple et list peuvent contenir plusieurs fois une même valeur :

s = "ababaabb"
t = (1,2,1,2,1,1,2,2)
l = [1,2,1,2,1,1,2,2]

Types arbitraires

Les str ne contiennent que des caractères, des chaînes de longueur 1. En revanche, les tuple et list peuvent contenir des valeurs de types différents :

t = (1, "abc", 1.0, True, 6.0)
l = [1, "abc", 1.0, True, 6.0]

Un tuple ou une list peut même contenir d'autres tuple ou list !

t = ((1,2), [0,4])
l = [(1,2), [0,4]]

Attention

Avoir des types arbitraires dans des list ou des tuple peut être source d'erreurs. En général, on préférera n'avoir que des valeurs d'un seul type dans une séquence.

Opérateur in

On peut vérifier si une valeur est présente dans une séquence avec l'opérateur in :

print("a" in "abcd")
print("e" in "abcd")

affiche

True
False
print(2 in (1,2,3))
print(4 in (1,2,3))

affiche

True
False
print(2 in [1,2,3])
print(4 in [1,2,3])

affiche

True
False

Pour les chaînes, on peut vérifier si chaine est présente.

print("bc" in "abcd")
print("cb" in "abcd")

affiche

True
False

Pour tuple et list, celà vérifie seulement si la valeur est présente en tant que telle, et non pas si ses éléments sont présents et se suivent :

print((1,2) in (1,2,3))
print([1,2] in (1,2,3))

affiche

False
False

Celà vient du fait que (1,2) in (1,2,3) teste si le tuple (1,2) est présent dans (1,2,3), et pas si 1 et 2 sont présents et se suivent dans (1,2,3).

print((1,2) in ((2,3),(1,2)))
print([1,2] in ([2,3],[1,2]))

affiche

True
True
print([1,2] in [1,2,3])
print((1,2) in [1,2,3])

affiche

False
False

Celà vient du fait que [1,2] in [1,2,3] teste si la list [1,2] est présente dans [1,2,3], et pas si 1 et 2 sont présents et se suivent dans [1,2,3].

print([1,2] in [[2,3],[1,2]])
print((1,2) in [(2,3),(1,2)])

affiche

True
True

Exercice : double consonnes

Implantez la fonction suivante:

def double_consonne(s):
    """s une chaine contenant un mot de français écrit sans accent.
    retourne True si s contient une double consonne. False sinon.

    exemple:
    double_consonne("contrepetrie") retourne False
    double_consonne("appeller") retourne True
    double_consonne("attaque") retourne True
    """
    pass

Commencez par implanter la fonction suivante :

def contient_double(c, s):
    """c une chaine contenant un seul caractère. s une chaîne.
    retourne True si s contient c + c, False sinon.

    exemple :
    contient_double("l", "appeller") retourne True
    contient_double("t", "appeller") retourne False
    """
    pass

Utilisez l'opérateur in pour implanter la fonction contient_double.

Vous pouvez implanter la fonction double_consonne en utilisant une boucle for pour parcourir la chaine à tester, et donc tester chaque caractère.

def contient_double(c, s):
    """c une chaine contenant un seul caractère. s une chaîne.
    retourne True si s contient c + c, False sinon.

    exemple :
    contient_double("l", "appeller") retourne True
    contient_double("t", "appeller") retourne False
    """
    return "c" + "c" in s

def double_consonne(s):
    """s une chaine contenant un mot de français écrit sans accent.
    retourne True si s contient une double consonne. False sinon.

    exemple:
    double_consonne("contrepetrie") retourne False
    double_consonne("appeller") retourne True
    double_consonne("attaque") retourne True
    """
    trouve = False 
    for c in s:
        if double_consonne(c,s):
            trouve = True
    return trouve
def contient_double(c, s):
    """c une chaine contenant un seul caractère. s une chaîne.
    retourne True si s contient c + c, False sinon.

    exemple :
    contient_double("l", "appeller") retourne True
    contient_double("t", "appeller") retourne False
    """
    return "c" + "c" in s


def double_consonne(s):
    """s une chaine contenant un mot de français écrit sans accent.
    retourne True si s contient une double consonne. False sinon.

    exemple:
    double_consonne("contrepetrie") retourne False
    double_consonne("appeller") retourne True
    double_consonne("attaque") retourne True
    """
    for c in s :
        if contient_double(c, s):
            ## On peut retourner directement dans une boucle,
            ## Attention toutefois, ça peut baisser la lisibilité 
            ## du code si la boucle est compliquée
            return True

On aurait aussi pu ne pas utiliser de fonction intermédiaire. Le code est alors plus rapide à écrire, mais on perds alors l'expressivité qui était donnée par le nom de la fonction itermédiaire

def double_consonne(s):
    """s une chaine contenant un mot de français écrit sans accent.
    retourne True si s contient une double consonne. False sinon.

    exemple:
    double_consonne("contrepetrie") retourne False
    double_consonne("appeller") retourne True
    double_consonne("attaque") retourne True
    """
    for c in s :
        if c + c in s:
            ## On peut retourner directement dans une boucle,
            ## Attention toutefois, ça peut baisser la lisibilité 
            ## du code si la boucle est compliquée
            return True

TODO (prof) ajout version avec tests !

Exercice : est-ce qu'une matière est disponible ?

Implantez un programme qui demande à un utilisateur de rentrer le nom d'une matière, puis dit à l'utilisateur si la matière est disponible ("maths" ou "NSI" ou "SVT" ou "physique") ou non. Vous devez utilisez au maximum un if et un else.

Exemples de traces :

Matière ? Histoire
Cette matière n'est pas disponible !
Matière: maths
Cette matière est disponible !

Utilisez un tuple (ou une list) pour stocker la liste des matières !

Utilisez in pour vérifier si une valeur est dans le tuple.

matieres = ("maths", "physique", "SVT", "NSI")

r = input("Matière ? ")
if r in matieres:
    print("Cette matière est disponible !")
else :
    print("Cette matière n'est pas disponible !")

TODO (prof) ajouter un exo pour list

Egalité : Opérateur ==

L'opérateur == permet de vérifier si deux séquences de même types contiennent les mêmes valeurs dans le même ordre.

print("abcd" == "abcd")
print("dcab" == "dcab")

affiche

True
False
print((1,2,3) == (1,2,3))
print((3,2,1) == (1,2,3))

affiche

True
False
print([1,2,3] == [1,2,3])
print([3,2,1] == [1,2,3])

affiche

True
False

Si les séquences sont de types différents, l'opérateur renvoie toujours False !

print("123" == ('1','2','3'))
print("123" == ['1','2','3'])
print([1,2,3] == (1,2,3))

affiche

False
False
False

L'opérateur s1 != s2 revient à utiliser not (s1 == s2).

Exercice : egalité entre list et tuple

Implémentez la fonction suivante :

def egal(t,l):
    """t un tuple 
    l une list
    retourne True si t contient les mêmes valeurs que l et dans le même ordre, False sinon

    Exemple:
    egal((1,2,3),[1,2,3]) retourne True
    egal((1,2,3),[1,2,3,4]) retourne False
    egal((1,2,3),[1,2,2]) retourne False
    """
    pass

Vous pouvez utiliser une boucle for ou while pour comparer les deux, mais cette solution est compliquée !

Sinon, vous pouvez transformer la list en tuple à l'aide de la fonction tuple

Ou encore, vous pouvez transformer le tuple en list avec la fonction list.

On transforme la list en tuple :

def egal(t,l):
    """t un tuple 
    l une list
    retourne True si t contient les mêmes valeurs que l et dans le même ordre, False sinon

    Exemple:
    egal((1,2,3),[1,2,3]) retourne True
    egal((1,2,3),[1,2,3,4]) retourne False
    egal((1,2,3),[1,2,2]) retourne False
    """
    return t == tuple(l)

ou vice-versa, le tuple en list :

def egal(t,l):
    """t un tuple 
    l une list
    retourne True si t contient les mêmes valeurs que l et dans le même ordre, False sinon

    Exemple:
    egal((1,2,3),[1,2,3]) retourne True
    egal((1,2,3),[1,2,3,4]) retourne False
    egal((1,2,3),[1,2,2]) retourne False
    """
    return list(t) == l

Cette solution est beaucoup moins concise, et aussi plus difficile à écrire. La solution concise lui est donc préférable.

def egal(t,l):
    """t un tuple 
    l une list
    retourne True si t contient les mêmes valeurs que l et dans le même ordre, False sinon

    Exemple:
    egal((1,2,3),[1,2,3]) retourne True
    egal((1,2,3),[1,2,3,4]) retourne False
    egal((1,2,3),[1,2,2]) retourne False
    """
    if len(t) != len(l): ## les deux séquences ne sont pas de même longueur
        return False
    i = 0
    ## On va comparer 2 a 2 les éléments de t et l, dans l'ordre.
    ## tant qu'on trouve des éléments deux à deux égaux, on 
    ## continue, sinon on s'arrête.
    while i < len(t) and e[i] == l[i]: ##rappel, ici len(t) == len(l).
        i = i + 1
    ## ici, si i < len(t), alors on n'a pas parcouru tous les éléments, et 
    ## donc on est sorti de la boucle à cause d'une différence
    ## Si on a pas trouvé de différences (les séquences sont égales), 
    ## alors i == len(t)
    return i == len(t) 

TODO (prof) ajouter un schéma ?

Tranche : opérateur []

L'opérateur [] sur les séquences permet aussi d'accéder à plusieurs éléments en même temps dans la séquence, en spécifiant un intervalle de positions, de la manière suivante :

On considère que `s = "abcdef"

syntaxe description exemple
[pos] caractère en position pos s[1] vaut "b"
[deb:fin] caractères de deb (inclus) à fin (exclus) s[2:4] vaut "cd"
[deb:] caractères à partir de deb (inclus) s[2:] vaut "cdef"
[:fin] caractères jusqu'à fin (exclus) s[:4] vaut "abcd"

On considère que t = ('a','b','c','d','e','f')

syntaxe description exemple
[pos] élément en position pos t[1] vaut ('b')
[deb:fin] éléments de deb (inclus) à fin (exclus) t[2:4] vaut ('c', 'd')
[deb:] éléments à partir de deb (inclus) t[2:] vaut ('c', 'd', 'e', 'f')
[:fin] éléments jusqu'à fin (exclus) t[:4] vaut ('a', 'b', 'c', 'd')

On considère que l = ('a','b','c','d','e','f')

syntaxe description exemple
[pos] élément en position pos l[1] vaut ['b']
[deb:fin] éléments de deb (inclus) à fin (exclus) l[2:4] vaut ['c', 'd']
[deb:] éléments à partir de deb (inclus) l[2:] vaut ['c', 'd', 'e', 'f']
[:fin] éléments jusqu'à fin (exclus) l[:4] vaut ['a', 'b', 'c', 'd']

Exercice : i premiers caractères

Implantez la fonction suivante:

def i_premiers(s, i):
    """s une chaine, i un entier, i > 0 , i < len(s)
    retourne les i premiers caractères de s

    i_premiers("abcd", 2) vaut "ab"
    """
    assert i < len(s)
    pass

Il vous faudra sans doute utiliser l'opérateur [] et des :. Regardez le tableau dans le cours pour la syntaxe exacte.

def i_premiers(s, i):
    """s une chaine, i un entier, i > 0 , i < len(s)
    retourne les i premiers caractères de s

    i_premiers("abcd", 2) vaut "ab"
    """
    assert i < len(s)
    return s[:i]

Exercice : deux deux

Implantez la fonction suivante :

def deux_deux(a, b):
    """a, b des chaines de longueur 4
    retourne une chaine composée des deux premiers caractères de a, et des deux derniers caractères de b

    deux_deux("abcd", "efgh") vaut "abgh"
    """
    assert len(a) == 4 and len(b) == 4
    pass

Vous devrez utiliser l'opérateur [] et des :. regardez le tableau dans le cours pour la syntaxe exacte.

Vous aurez aussi besoin de l'opérateur +.

def deux_deux(a, b):
    """a, b des chaines de longueur 4
    retourne une chaine composée des deux premiers caractères de a, et des deux derniers caractères de b

    deux_deux("abcd", "efgh") vaut "abgh"
    """
    assert len(a) == 4 and len(b) == 4
    return a[:2] + b[3:]

Alternativement, on aurait pu partir de la fin. de b, en utilisant un indice négatif

def deux_deux(a, b):
    """a, b des chaines de longueur 4
    retourne une chaine composée des deux premiers caractères de a, et des deux derniers caractères de b

    deux_deux("abcd", "efgh") vaut "abgh"
    """
    assert len(a) == 4 and len(b) == 4
    return a[:2] + b[-2:]

Exercice : moite-moite

Implantez la fonction suivante:

def moite_moite(a, b):
    """a, b des chaînes non vides
    retourne une chaîne composée de la première moitié de a, et de la seconde moitié de b


    moite_moite("abcdef", "ghijk") vaut "abcjk"
    """
    assert a != "" et b != ""
    pass

La fonction len permet de connaître la longueur d'une chaîne.

La longueur d'une chaine est un entier.

On peut diviser les entiers par 2.

def moite_moite(a, b):
    """a, b des chaînes non vides
    retourne une chaîne composée de la première moitié de a, et de la seconde moitié de b


    moite_moite("abcdef", "ghijk") vaut "abcjk"
    """
    assert a != "" et b != ""
    moit_a = len(a) / 2 ## indice à la moitié de a
    moit_b = len(b) / 2 ## incice à la moitié de b
    return a[:moit_a] + b[:moit_b]

TODO (prof) ajouter des exercices pour tuple et list ici

Choix du type de séquence

Pour stocker une séquence de caractères, c'est à dire du texte, str est un choix évident dans la plupart des cas.

Pour des séquences contenant des valeurs d'autres types que des caractères (ou des chaînes), nous sommes obligés d'utiliser tuple ou list. Mais comment choisir ?

Jusqu'à présent, on n'a pas vu de différence entre tuple et list. Pourtant, il existe une différence majeure :

Les list peuvent être modifiées, alors que les tuple ne peuvent pas l'être.

Cette différence est tellement importante qu'elle fera l'objet du prochain chapitre.