IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

tableau de liste trié selon un élément de la liste


Sujet :

Python

  1. #1
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Par défaut tableau de liste trié selon un élément de la liste
    Bonjour,

    soit le fichier CSV qui commence comme cela et contient 183000 lignes non triées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    ENFANT_SEXE;ENFANT_PRENOM;ANNEE;DEP_LIBELLE;DEP_CODE;NOMBRE_OCCURRENCES
    Garçons;ELIOTT;2016-01-01;Loire-Atlantique;44;41.0
    Garçons;ELLIOT;2001-01-01;Loire-Atlantique;44;6.0
    Garçons;ELLIOT;2008-01-01;Loire-Atlantique;44;9.0
    Garçons;ELOI;1906-01-01;Loire-Atlantique;44;4.0
    Garçons;ELOI;2011-01-01;Loire-Atlantique;44;6.0
    Garçons;ELOI;2017-01-01;Loire-Atlantique;44;3.0
    Je le mets dans un tableau:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    import csv
    f = open("234400034_001-002_prenoms-maj2017.csv", "r",  encoding='utf-8')
    c = csv.reader(f, delimiter=';')
    tableau = []
    cmpt = 0
    for ligne in c:
        tableau.append(ligne)
        cmpt=cmpt+1
        if cmpt%1000 == 0:
            print (cmpt," lignes lues")
    f.close()

    Je veux obtenir un nouveau tableau trié par ordre alphabétique sur la deuxième colonne correspondant aux prénoms.

    Merci pour votre aide.

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    NB: le code doit être présenté entre les tags de code (le '#' en haut et à droite de la fenêtre d'édition)

    Voilà un exemple de code (Python 3) pour ton problème, en partant du principe que le fichier tiendra en mémoire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import csv
     
    # lit le fichier "fichier.csv"
    tableau = []
    cmpt = 0
    with open("fichier.csv", "r", encoding='utf-8') as f1:
        for ligne in csv.reader(f1, delimiter=';'):
            tableau.append(ligne)
            cmpt += 1
     
    print(cmpt," lignes lues")
     
    # retire la ligne de titre en 1ère position
    lignetitre = tableau.pop(0)
     
    # trie le tableau selon le 2ème champ du tableau
    tableau.sort(key=lambda v: v[1])
     
    # remet la ligne de titre en 1ère position
    tableau.insert(0, lignetitre)
     
    # écrit le tableau trié dans le fichier "fichier2.csv"
    with open('fichier2.csv', 'w', newline='', encoding='utf-8') as f2:
        c2 = csv.writer(f2, delimiter=';', quoting=csv.QUOTE_MINIMAL)
        for ligne in tableau:
            c2.writerow(ligne)

  3. #3
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Par défaut
    Super, ça marche, un grand merci tyrtamos.

    Et en plus, je comprends tout,... enfin presque tout: En fait la ligne clef m'échappe un peu.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tableau.sort(key=lambda v: v[1])
    Qui tente de m'expliquer?

    Merci

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Salut,

    Le tuto. sur comment trier avec Python qui vient avec la documentation standard est un bon début...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par gilles2508 Voir le message
    En fait la ligne clef m'échappe un peu.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tableau.sort(key=lambda v: v[1])
    Qui tente de m'expliquer?
    Le tri des éléments d'une liste suppose une comparaison entre chacun d'entre eux pour savoir lequel est avant l'autre.

    Mais ici, on a une liste composée de sous-listes, chacune représentant une ligne comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ['Garçons', 'ELLIOT', '2001-01-01', 'Loire-Atlantique', '44', '6.0']
    Et comme tu veux que le tri se fasse sur le 2ème champ de chaque ligne, on met:

    pour dire à sort: pour les comparaisons, au lieu de prendre la sous-liste v, tu prends son 2ème champ v[1]

    Pour faire un tri sur les dates, il suffirait de mettre key=lambda v: v[2]

    ok?

  6. #6
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Par défaut
    Merci,
    c'est de plus en plus clair, mais pour aller au boût, je vous sollicite encore. N'hésitez pas à me rectifier si je dis des bourdes:

    la méthode sort() attend une clef de tri.
    "key = " est suivi d'une fonction. lamda permet l'écriture implicite d'une fonction qui prend comme argument "v" et renvoie v[1]

    Que représente "v"? Une ligne (liste) du fichier certainement, mais comment cela se fait-il?

    Gilles

  7. #7
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par gilles2508 Voir le message
    Que représente "v"? Une ligne (liste) du fichier certainement, mais comment cela se fait-il?
    lambda déclare une fonction qui sera appliquée à chaque élément de la liste à trier (ici chaque élément est une sous-liste pour chaque ligne), et v n'est qu'un argument de fonction: tu l'appelles comme tu veux.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    key=lambda nimportequoipourvuquecamousse: nimportequoipourvuquecamousse[1]
    fonctionnerait aussi bien!

  8. #8
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Par défaut
    Merci tyrtamos pour tout,

    je n'ai pas encore bien compris la dernière réponse, ...mais Ca va mousser et demain matin j'aurai compris.

    Bonne journée.

    Gilles

  9. #9
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2018
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 41
    Par défaut
    Salut,
    Il reste un inconvénient avec le code suivant :
    Citation Envoyé par tyrtamos Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    # trie le tableau selon le 2ème champ du tableau
    tableau.sort(key=lambda v: v[1])
    c'est que le tableau n'est pas vraiment trié... si les données contiennent des caractères accentués.
    Ceci est dû au fait que ces caractères viennent après les autres dans l'ordre des caractères unicode.
    Pour éviter cela, il faut les convertir avant tri en leur équivalent non accentué. Ce qui se fait très bien avec le trop peu connu module unidecode.
    Exemple simplifié :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    import unidecode
    tableau = [
    	['garçons','éliot'],
    	['garçons','eliot'],
    	['garçons','alceste'],
    	['garçonss','roger'],
    	]
    print(tableau)
    tableau.sort(key=lambda v: v[1])
    print(tableau)
    tableau.sort(key=lambda v: unidecode.unidecode(v[1]))
    print(tableau)
    Ce module s'installe avec pip (pip3 install unidecode).
    Voici le résultat du code précédent :
    [['garçons', 'éliot'], ['garçons', 'eliot'], ['garçons', 'alceste'], ['garçonss', 'roger']]
    [['garçons', 'alceste'], ['garçons', 'eliot'], ['garçonss', 'roger'], ['garçons', 'éliot']]
    [['garçons', 'alceste'], ['garçons', 'eliot'], ['garçons', 'éliot'], ['garçonss', 'roger']]
    La troisième ligne est la seule version de la liste qui soit véritablement triée.

  10. #10
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Citation Envoyé par jmbain Voir le message
    c'est que le tableau n'est pas vraiment trié... si les données contiennent des caractères accentués.
    Ceci est dû au fait que ces caractères viennent après les autres dans l'ordre des caractères unicode.
    Bien vu! C'est même encore pire que ça, puisque dans les polices de caractères courantes, non seulement les caractères accentués sont derrière tous les autres caractères, mais les caractères minuscules sont derrière les majuscules.

    Exemples:
    'é' est après le 'z'
    'a' est après le 'Z'

    On peut utiliser le module "unicodedata" en créant une fonction qui va supprimer les accents et tout passer en majuscules:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from unicodedata import normalize, combining
     
    def majuscsa(ch):
        """Convertit la chaine ch (unicode) en majuscules non accentuées
           utilise unicodedata.normalize et unicodedata.combining
        """
        # conv. de minuscule en majuscule avec conservation des accents éventuels
        ch = ch.upper()
        # suppression des accents qui restent
        chnorm = normalize('NFKD', ch)
        return "".join([c for c in chnorm if not combining(c)])
    Avec cette fonction, l'instruction de tri deviendra tout simplement:

    tableau.sort(key=lambda v: majuscsa(v[1]))

    Mais le résultat n'est pas encore parfait, puisque les caractères accentués, ayant perdu leur accent, apparaîtront dans l'ordre initial de la liste. Et donc, on pourra avoir: "xxéx", "xxex", "xxèx", etc...

    Il faudrait donc faire un vrai tri français comme le fait le dictionnaire! Et là, ça se gâte un peu...

    Le document le plus clair que j'ai trouvé est un document canadien: http://www-clips.imag.fr/geta/gilles...-francais.html. On voit bien que le français est bourré de vacheries...

    Par exemple, il est reconnu comme ordre de priorité entre les caractères français:

    aA àÀ âà
    cC çÇ
    eE éÉ èÈ êÊ ëË
    iI îÎ ïÏ
    oO ôÔ
    uU ùÙ ûÛ üÜ
    yY ÿŸ

    Voilà cependant un code que j'ai développé et qui respecte les exemples donnés du document canadien:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #! /usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import locale
     
    class Compfr:
        """comparaison de 2 chaines unicode selon le dictionnaire français
        """
        def __init__(self):
            self.loc = locale.getlocale() # stocke la locale courante
            self.espinsec = '\xA0' # espace insécable
     
        def __call__(self, v1, v2):
            # retire les tirets et les blancs insécables
            v1 = v1.replace('-', '')
            v1 = v1.replace(self.espinsec, '')
            v2 = v2.replace('-', '')
            v2 = v2.replace(self.espinsec, '')
            # calcule la comparaison selon la locale
            locale.setlocale(locale.LC_ALL, '')
            comp = locale.strcoll(v1, v2)
            #retour à la locale courante
            locale.setlocale(locale.LC_ALL, self.loc) 
            # retour du résultat de la comparaison
            return comp
    Et voilà des exemples d'utilisation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    from functools import cmp_to_key
     
    L = ['pécher', 'pèche', 'pêcher', 'PÉCHÉ', 'péché', 'PÊCHE', 'pêche', 'PÈCHE']
    print(L)
    compfr = Compfr()
    L2 = sorted(L, key=cmp_to_key(compfr))
    print(L2)
    Ce qui affiche:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ['pécher', 'pèche', 'pêcher', 'PÉCHÉ', 'péché', 'PÊCHE', 'pêche', 'PÈCHE']
    ['pèche', 'PÈCHE', 'pêche', 'PÊCHE', 'péché', 'PÉCHÉ', 'pécher', 'pêcher']
    Etc...

    On voit que, comme il s'agit d'une comparaison entre 2 éléments (à cause de locale.strcoll), on utilise cmp_to_key du module functools.

    Pour le problème de tri de ce fil, cela donnerait (j'ai mis une majuscule au 2ème 'eliot'):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    L = [['garçons', 'éliot'], ['garçons', 'Eliot'], ['garçons', 'eliot'], ['garçons', 'alceste'], ['garçons', 'roger']]
    print(L)
    compfr = Compfr()
    L.sort(key=cmp_to_key(lambda x, y:compfr(x[1],y[1])))
    print(L)
    Ce qui affiche:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [['garçons', 'éliot'], ['garçons', 'Eliot'], ['garçons', 'eliot'], ['garçons', 'alceste'], ['garçons', 'roger']]
    [['garçons', 'alceste'], ['garçons', 'eliot'], ['garçons', 'Eliot'], ['garçons', 'éliot'], ['garçons', 'roger']]

  11. #11
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Salut,

    Citation Envoyé par tyrtamos Voir le message
    On voit que, comme il s'agit d'une comparaison entre 2 éléments (à cause de locale.strcoll), on utilise cmp_to_key du module functools.
    key=locale.strxfrm est assez bon (et probablement plus rapide) excepté pour les '-' (qui se remplacent).
    L'internationalisation (I18N) date de la fin des années 80 et tout le boulot a été réalisé assez bien dans locale avec ses collations spécifiques... non sans mal car, les bugs donnaient lieu a des débats plutôt exotiques.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  12. #12
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Citation Envoyé par wiztricks Voir le message
    key=locale.strxfrm est assez bon (et probablement plus rapide) excepté pour les '-' (qui se remplacent).
    Merci wiztricks, je vais essayer. Ce serait bien que ça permette de ne pas utiliser cmp_to_key.

  13. #13
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2018
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2018
    Messages : 41
    Par défaut
    Hello,
    C'est bien gentil tout ça, mais guère pythonesque relativement à la fonction de tri standard.
    Je m'explique : nous avons certes des solutions élégantes pour trier localement, mais dans la mesure où il existe un nombre significatif de programmeurs travaillant sur des caractères internationaux, pourquoi n'y aurait-il pas une prise en compte directe du problème dans le sort ? Ceci éviterait import, déclaration et utilisation de fonction pour un régler un problème finalement assez récurrent. Ce qui est pondéré par le fait que très fréquemment les données sont stockées dans un SGBD qui prend en charge le problème, ce qui évite de s'en préoccuper en python, mais malgré tout, un sort plus évolué serait quand même bien utile, à mon humble avis.
    L'un d'entre vous a-t-il déjà entendu parler d'un PEP sur le sujet ? Je pose la question car je n'en ai pas trouvé trace, mais c'est assez difficile de chercher sur ce genre de chose.
    Pensez-vous qu'il serait utile de travailler sur la présentation d'un PEP proposant l'intégration au sort des solutions évoquées ?

  14. #14
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Citation Envoyé par jmbain Voir le message
    mais dans la mesure où il existe un nombre significatif de programmeurs travaillant sur des caractères internationaux, pourquoi n'y aurait-il pas une prise en compte directe du problème dans le sort ?
    Parce que passer par les "locale" est la solution choisie à la fin des années 80s et qui est utilisée dans tous les langages de programmation (Python n'est pas une exception).
    Après on peut se demander pourquoi avoir choisi cela plutôt que d'en faire le "défaut".

    C'est essentiellement parce que nous avions déjà (à l'époque) un tas d'applications existantes qu'il était impensable de mettre à jour/revalider/.... en changeant le défaut de façon aussi "violente".

    D'autant que dans le tas des applications existantes, nombre d'entre elles tournent sans qu'on s'en inquiète dans leur coin (le "legacy" comme on dit) et assurent des missions vitales pour la société (santé, pompiers, défense, surveillance de centrales nucléaires,...).

    Vous êtes peut être trop jeune mais vous avez peut être entendu parler du bug de l'an 2000. Le problème potentiel étant avéré, impossible de ne rien faire... et ce fut un chantier mémorable qui a couté des millions d'années hommes de boulot pour que çà se passe bien: une galère!

    Donc chaque fois qu'on bouge, on essaie d'éviter de créer des problèmes parce qu'on est en incapacité d'en anticiper l'ensemble des conséquences: vous voulez utiliser les locale, très bien et si c'est une nouvelle fonctionnalité avec laquelle vous construisez votre application, celles qui n'ont pas été construites avec fonctionnent inchangées.
    Et tout le monde est content.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 082
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 082
    Par défaut
    Bonjour,

    Ce n'est pas compris dans la méthode sort, mais il y a une certaine liberté grâce au paramètre key.

    On pourrait par exemple utiliser PyICU. Un exemple sur cette page.

    En python, il est rare de ne pas trouver des solutions simples à un problème.

    Alors oui il faut installer une librairie, importer un module, mais c'est encore pas trop complexe,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> import icu
    >>> collator = icu.Collator.createInstance(icu.Locale('fr_FR'))
    >>> L = ['pécher', 'pèche', 'pêcher', 'PÉCHÉ', 'péché', 'PÊCHE', 'pêche', 'PÈCHE']
    >>> sorted(L, key=collator.getSortKey)
    ['péché', 'PÉCHÉ', 'pèche', 'PÈCHE', 'pêche', 'PÊCHE', 'pécher', 'pêcher']
    P.S Pour installer PyICU, il faut une librairie nommée sur linux libicu-dev

    Sur ma debian,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sudo apt install libicu-dev
    Je trouve que c'est un compromis raisonnable...

  16. #16
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Ce n'est pas compris dans la méthode sort, mais il y a une certaine liberté grâce au paramètre key.

    On pourrait par exemple utiliser PyICU. Un exemple sur cette page.
    La bibliothèque locale est déjà incluse dans les bibliothèques standard. Après on peut toujours ajouter une couche au dessus (une bibliothèque externe), si vous pensez que çà va vous simplifier la vie... mais si c'est juste pour écrire key=collator.getSortKey à la place de key=locale.strxfrm: vous avez juste packagé un vieux machin avec un truc qui se veut nouveau. Ca s'appelle du marketing, pas de l'informatique.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  17. #17
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 082
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 082
    Par défaut
    Je ne sais pas, tu as probablement raison, j'ai tout de même fait un test, et je me rend compte que le résultat n'est pas identique,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    In [5]: L = ['pécher', 'pèche', 'pêcher', 'PÉCHÉ', 'péché', 'PÊCHE', 'pêche', 'PÈCHE']                                                                                                                             
     
    In [6]: sorted(L, key=collator.getSortKey)                                                                                                                                                                         
    Out[6]: ['péché', 'PÉCHÉ', 'pèche', 'PÈCHE', 'pêche', 'PÊCHE', 'pécher', 'pêcher']
     
     
    In [7]: import locale                                                                                                                                                                                              
     
     
    In [8]: sorted(L, key=locale.strxfrm)                                                                                                                                                                              
    Out[8]: ['PÈCHE', 'PÉCHÉ', 'PÊCHE', 'pèche', 'pécher', 'péché', 'pêche', 'pêcher']
    Alors peut-être ai-je omis une subtilité ?

    EDIT: Je viens de lire un paragraphe de Victor Stinner

    Citation Envoyé par Victor Stinner
    In my experience, the locale module is error-prone and not reliable, especially if you want portability. It just uses functions provided by the OS. And the locales (LC_CTYPE, LC_MESSAGE, etc.) are process-wide which become a major issue if you want to serve different clients using different locales... Windows supports a different locale per thread if I remember correctly.
    It would be more reliable to use a good library like ICU. You may try: https://pypi.python.org/pypi/PyICU
    qui a l'air d'aller dans le sens PyICU.

    Source: Message de Victor

  18. #18
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 762
    Par défaut
    Salut,

    Citation Envoyé par fred1599 Voir le message
    Alors peut-être ai-je omis une subtilité ?
    De faire un locale.setlocale(....) avant.

    EDIT: Je viens de lire un paragraphe de Victor Stinner

    qui a l'air d'aller dans le sens PyICU.
    "locale" est une fonctionnalité réalisée par les OS qu'utilisent les différents langages.
    Ses fonctionnalités sont définies par des standards ISO.
    Normalement, on devrait avoir les mêmes fonctionnalités sur les différentes plate-formes (c'est la cause du bug reporté...)
    Et si ce n'est pas le cas, blâmer l'implémentation de l'environnement système (qui sont en charge de...) plutôt que le langage qui se contente de les utiliser.

    Cela peut produire une évolution du "standard" avec des tests qui permettent de vérifier la conformité de l'implémentation... mais si les développeurs de tout langage s'embarquent à implémenter leurs "corrections", çà réduit d'autant l'intérêt d'avoir des bibliothèques "communes" et des "standards".

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  19. #19
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 840
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par wiztricks Voir le message
    Vous êtes peut être trop jeune mais vous avez peut être entendu parler du bug de l'an 2000
    Moi je m'en souviens.
    Le soir du 31/12/1999, on avait reçu des gyrophares de police et on était autorisé à foncer sans limitation de vitesse sur tout site qui nous aurait appelé. J'avais trop kiffé cette nuit là
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  20. #20
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je trouve pour ma part étonnant que Python ait fourni un moyen tout fait pour trier selon le dictionnaire français, malgré son extrême complexité. Je suppose qu'il en est de même pour les autres langues qui ont des signes "diacritiques" (caractères accentués, ...). Et je confirme (merci wiztricks) que locale.strxfrm marche très bien et permet de se passer de cmp_to_key.

    Cependant, il y a des parties de l'algorithme de comparaison qui sont difficiles à comprendre, voire carrément inadaptées aux tris qui peuvent nous intéresser. Par exemple, dans certains cas, l'ordre des mots est déterminé en partant de la fin des mots et non à leur début. Exemple: d'après le document canadien, l'ordre de ['élève', 'élevé'] est correct, alors qu'on donne par ailleurs des priorités "eEéÉèÈêÊëË": ce n'est pas logique. Par ailleurs, les mots que nous devons trier peuvent comporter d'autres caractères que ceux des mots français du dictionnaire, comme les chiffres ou des caractères qui ne sont ni alphabétiques, ni numériques ("!?,.:_#'\ /, etc...).

    En ce qui me concerne, pour de nombreux tris que j'ai eu à faire, j'ai cherché une solution "perso" qui soit plus élaborée que l'ASCII, sans aller jusqu'à la complexité du dictionnaire français.

    Voilà comment je fais:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #! /usr/bin/python3
    # -*- coding: utf-8 -*-
     
    #############################################################################
    alphafr = r""" !"#$%&'()*+,-./0123456789:;<=>?@[\]^_`{|}~ €""" + \
              r"""aAàÀâÂäÄåÅæÆbBcCçÇdDeEéÉèÈêÊëËfFgGhHiIîÎïÏjJ""" + \
              r"""kKlLmMnNoOôÔöÖœŒpPqQrRsStTuUùÙûÛüÜvVwWxXyYÿŸzZ"""
    lgalphafr = len(alphafr)
     
    #############################################################################
    def compalphafr(v1, v2):
        """comparaison de l'ordre alphanumérique des chaines v1 et v2:
           renvoie -1 si v1<v2, 0 si v1==v2, et +1 si v1>v2
           dépendance: alphafr et lgalphafr
        """
        lg1, lg2 = len(v1), len(v2)
        for i in range(0, min([lg1, lg2])):  # min(): mot le + court de v1 et v2
            i1 = alphafr.find(v1[i])  # indice du caractère v1[i] dans alphafr
            if i1 < 0:
                i1 = lgalphafr + ord(v1[i])  # v1[i] n'est pas dans alphafr
            i2 = alphafr.find(v2[i])  # indice du caractère v2[i] dans alphafr
            if i2 < 0:
                i2 = lgalphafr + ord(v2[i])  # v2[i] n'est pas dans alphafr
            if i1 != i2:
                return (i1 > i2) - (i1 < i2)  # simul. de la fonct. cmp de Python 2
        # les lg 1ers caractères sont identiques: le mot le plus court est avant
        return (lg1 > lg2) - (lg1 < lg2)  # simulation de la fonct. cmp de Python 2
    Cela veut dire qu'on définit dans alphafr l'ordre dans lequel les caractères doivent apparaître dans le tri, et que cet ordre est examiné caractère par caractère de gauche à droite dans la comparaison des mots.

    Exemple d'utilisation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    from functools import cmp_to_key
     
    L = ['élève', 'élevé']
    L2 = sorted(L, key=cmp_to_key(compalphafr))
    print(L2)
    ['élevé', 'élève']
    C'est comme ça que je trie, par exemple, mes listes de fichiers, et je comprends beaucoup mieux dans quel ordre ils sont.

    Et, bien sûr, rien n'empêche de modifier l'ordre des caractères de alphafr pour s'adapter à des tris particuliers. On peut aussi sophistiquer le traitement en remplaçant "æ" par "ae" avant la comparaison, etc...

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/04/2016, 14h07
  2. [PHP 5.5] supprimer un tableau (array) selon son élément
    Par aspkiddy dans le forum Langage
    Réponses: 8
    Dernier message: 10/09/2015, 14h56
  3. listes triées selon langue choisie (D7)
    Par lfa95 dans le forum Langage
    Réponses: 7
    Dernier message: 13/04/2011, 14h40
  4. [JDOM] Ajout d'éléments triés selon leur nom et problème de redondance.
    Par _fav_ dans le forum Format d'échange (XML, JSON...)
    Réponses: 3
    Dernier message: 05/08/2010, 11h24
  5. Réponses: 4
    Dernier message: 09/08/2006, 11h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo