Partage
  • Partager sur Facebook
  • Partager sur Twitter

renommer doublons dans liste

Sujet résolu
    20 mai 2015 à 8:51:32

    Bonjour, j'ai une liste de chaine de caractere, et j'aimerais modifier les doublons, par exemple j'ai:

    maliste=["Paul","Joe","Paul"]

    Je souhaiterais la transformer en :

    maliste=["Paul1","Joe","Paul2"]

    Je ne veut donc pas les supprimer.



    • Partager sur Facebook
    • Partager sur Twitter
      20 mai 2015 à 9:15:56

      Tu peux le faire via un dictionnaire :

      maliste=["Paul","Joe","Paul","Martine", "Joe", "Paul"]
      dic_occurences = {}
      
      for i in range(0, len(maliste)) :
      	element = maliste[i]
      	if element not in dic_occurences :
      		dic_occurences[element] = 1
      	else :
      		maliste[i] = maliste[i] + str(dic_occurences[element])
      		dic_occurences[element] += 1
      
      print maliste
      



      • Partager sur Facebook
      • Partager sur Twitter
        20 mai 2015 à 10:12:35

        Salut,

        Tu peux également utiliser une liste en intention. Par contre le code n'est pas forcément clair :p

        maliste=["Paul","Joe","Paul","Martine", "Joe", "Paul"]
        
        nv_lst = [elt if maliste.count(elt)==1
                else "{}{}".format(elt, maliste.count(elt)-maliste[ind+1:].count(elt))
                for ind, elt in enumerate(maliste)]

        PS: Avez-vous remarqué que l'ordre des étapes dans une intention (une compréhension) est différent si on a ou non la condition else.

        • Partager sur Facebook
        • Partager sur Twitter
        Précepte: Le mieux est l'ennemi du bien
          20 mai 2015 à 10:16:32

          Merci pour vos 2 solutions, j'ai pris celle de Jevanni, car elle est plus clair.
          • Partager sur Facebook
          • Partager sur Twitter
            20 mai 2015 à 10:20:44

            Ceci ne fonctionne pas puisque le premier «Paul» n'est pas renommé en «Paul1», de plus, un Counter serait plus judicieux qu'un dictionnaire, et ce n'est pas comme ça qu'on itère sur une liste en Python.

            Voici la solution que je propose :

            from collections import Counter
            
            maliste=["Paul","Joe","Paul","Martine", "Joe", "Paul"]
            
            # On compte le nombre d'occurrences de chaque nom
            occurrences = Counter(maliste)
            
            # On crée un dictionnaire répertoriant les suffixes à ajouter (pas de suffixe quand une seule occurrence)
            suffixes = {name: list(range(1, count + 1)) for name, count in occurrences.items() if count > 1}
            
            # On remplace les noms en ajoutant leur suffixe si besoin
            maliste = ['{}{}'.format(name, suffixes[name].pop(0)) if name in suffixes else name for name in maliste]
            

            EDIT: remplacement des 3 lignes du compteur (création d'un compteur vide puis ajout des éléments) par la création d'un compteur depuis la liste

            -
            Edité par entwanne 20 mai 2015 à 12:45:03

            • Partager sur Facebook
            • Partager sur Twitter
              20 mai 2015 à 10:24:56

              Ta solution est sympa Olygrim par contre je me demande si c'est pas un peu bourrin si on a une liste très très (très) longue, étant donné qu'au final tu dois avoir une complexité un peu de foufou avec ton count à chaque itération. Sinon oui, le changement avec le else m'a déjà emmerdé plus d'une fois (et la première fois rend un peu fou si tu ne sais pas) :)

              Edit pour entwanne : Ca va, on a juste à bouger une ligne pour avoir le comportement voulu ...

              maliste=["Paul","Joe","Paul","Martine", "Joe", "Paul"]
              dic_occurences = {}
               
              for i in range(0, len(maliste)) :
                  element = maliste[i]
                  if element not in dic_occurences : 
                  	dic_occurences[element] = 1
                  else : 
                  	dic_occurences[element] += 1
                  maliste[i] = maliste[i] + str(dic_occurences[element])
              
              print maliste

              Parfois il vaut mieux un exemple simple plutôt qu'un truc bourrin, même si c'est pas forcément bien codé, surtout quand il s'agit d'un problème "simple" comme ça. Donc sérieux osef de la boucle avec le range ...

              -
              Edité par Jevanni 20 mai 2015 à 10:31:02

              • Partager sur Facebook
              • Partager sur Twitter
                20 mai 2015 à 10:28:38

                @entwanne

                Tu peux directement utiliser ta liste en argument de Counter() pour avoir le compte. Merci à Sam&Max ^^

                occurrences = Counter(maliste)



                • Partager sur Facebook
                • Partager sur Twitter
                Précepte: Le mieux est l'ennemi du bien
                  20 mai 2015 à 10:31:52

                  "je me demande si c'est pas un peu bourrin si on a une liste très très (très) longue"

                  C'est exactement ce que je me suis dit, et au final une boucle classique me paraît plus pertinent (rien que pour éviter de calculer 2 fois maliste.count(elt)^^

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Précepte: Le mieux est l'ennemi du bien
                  Anonyme
                    20 mai 2015 à 10:34:18

                    Ta solution est sympa Olygrim par contre je me demande si c'est pas un peu bourrin si on a une liste très très (très) longue

                    Il ne faut pas sous estimé la méthode count, c'est un binding C très efficace... et avant d'arriver à la surpasser, il va falloir faire des tests avec d'autres solutions que celles proposées. Elle n'est certes pas la plus propre, mais je pense que c'est la plus efficace !

                    Cependant j'aime bien la solution pythonique d'entwanne, qui pour ce genre d'exercice est la solution qui me semble la plus lisible et maintenable à long terme.

                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 mai 2015 à 10:42:33

                      Jevanni a écrit:

                      Edit pour entwanne : Ca va, on a juste à bouger une ligne pour avoir le comportement voulu ...

                      Non, dans ta nouvelle monture, tu ajoutes un «1» même aux noms qui n'ont pas de doublons. Tu testes tes bouts de code avant de les poster ?

                      Olygrim a écrit:

                      Tu peux directement utiliser ta liste en argument de Counter() pour avoir le compte. Merci à Sam&Max ^^

                      Oui, merci, j'avais oublié cette possibilité.

                      Olygrim a écrit:

                      PS: Avez-vous remarqué que l'ordre des étapes dans une intention (une compréhension) est différent si on a ou non la condition else.

                      Que veux-tu dire par là ? Le mot-clef else est obligatoire dans l'opérateur ternaire. Tu peux avoir un if sans else dans les listes en intention, mais ça n'est pas un ternaire et ça ne se place pas au même endroit.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        20 mai 2015 à 10:45:33

                        "Donc sérieux osef de la boucle avec le range"

                        C'est marrant parce que la boucle range() m'a aussi fait tiquer :). Après c'est juste parce qu'on m'a souvent répété que c'était pas propre. Je n'ai pas le niveau pour débattre mais j'aurai plutôt utiliser enumerate() à la place:

                        for ind, elt in enumerate(maliste) :
                            if elt not in dic_occurences :
                                dic_occurences[elt] = 1
                            else :
                                dic_occurences[elt] += 1
                            maliste[ind] = maliste[ind] + str(dic_occurences[elt])

                        Par contre Jevanni ton résultat renvoie Martine1 au lieu de Martine :o


                        "Il ne faut pas sous estimé la méthode count"

                        Thx pour l'info oldP. Même si j'en abuse quand même pas mal (3 fois dans mon code:lol:). C'est d'ailleurs pour ça que j'étais pas trop satisfait de la qualité de ce code :honte:

                        -
                        Edité par Olygrim 20 mai 2015 à 10:46:08

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Précepte: Le mieux est l'ennemi du bien
                          20 mai 2015 à 10:49:33

                          "mais ça n'est pas un ternaire et ça ne se place pas au même endroit."

                          Et bien justement je ne connaissais pas cette distinction. Merci ^^

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Précepte: Le mieux est l'ennemi du bien
                          Anonyme
                            20 mai 2015 à 10:50:19

                            Même si j'en abuse quand même pas mal (3 fois dans mon code:lol:).

                            Si on souhaite quelque chose d'efficace, même si le nombre de boucles peut paraître aberrant, ce qu'on regardera c'est l'efficacité avant tout, mais si ce n'est pas ce qu'on recherche, je préfère la solution d'entwanne...

                            • Partager sur Facebook
                            • Partager sur Twitter
                              20 mai 2015 à 10:59:12

                              Olygrim a écrit:

                              "mais ça n'est pas un ternaire et ça ne se place pas au même endroit."

                              Et bien justement je ne connaissais pas cette distinction. Merci ^^

                              Voici un extrait de la documentation sur la syntaxe Python pour mieux comprendre:

                              https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries

                              comprehension ::= expression comp_for comp_for ::= "for" target_list "in" or_test [comp_iter] comp_iter ::= comp_for | comp_if comp_if ::= "if" expression_nocond [comp_iter]

                              En fait, il se trouve que le iffait partie intégrante de la syntaxe des listes en intention (ainsi que des générateurs, ensembles ou dictionnaires), permettant de filtrer les éléments. Par contre, l'expression à placer au début peut-être n'importe quelle expression python, ternaires inclus (... if ... else ...). Ainsi, il est possible d'écrire [elem + 1 if elem > 0 else elem for elem in elements if elem < 10]. J'avais mal compris ta question car je croyais que tu parlais d'ordre d'évaluation et non d'ordre dans l'écriture.

                              • Partager sur Facebook
                              • Partager sur Twitter
                                20 mai 2015 à 11:02:09

                                Oui mon code ne fonctionne pas correctement, je n'ai pas fait attention ce coup-ci, au temps pour moi.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  20 mai 2015 à 11:05:52

                                  J'avais modifier le code de Jevanni, pour avoir le comportement voulue.

                                  C'est quoi la différence entre la solution de Jevanni et celle de Olygrim/entwanne concrètement ? est elle plus performante ?

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    20 mai 2015 à 11:12:53

                                    Celle d'Etwanne est la plus pythonique. Si je lis le code d'Etwanne, je vois tout de suite ce qu'il veut faire. Si je lis le code de Jevanni, je me dis: il ré-invente la roue.

                                    Lequel est le plus performant? Tu peux faire quelques timeit, mais à mon avis c'est la solution d'Etwanne qui sera devant.

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      20 mai 2015 à 11:16:09

                                      Plusieurs choses :

                                      • Mon code n'a pas exactement le résultat voulu, contrairement aux deux autres solutions fournis si l'on recherche strictement ce que tu as présenté. Dans le 1er code que j'ai donné la 1ère occurrence n'a pas de "1" à la fin. Dans le second (qui est encore plus faux en fait), tous les noms, mêmes ceux présents une fois, ont un 1 lors de la 1ère occurrence.
                                      • Le second point du "débat" vient du fait que mon code n'est pas propre. Tout d'abord etwanne a présenté l'utilisation d'un module spécifique, ce qui rend le plus "agréable" (il n'y a pas besoin d'utiliser de dic). Dans un second temps j'utilise une boucle for avec un range, ce qui est d'habitude à éviter.
                                      • En terme de performance je pense que la solution d'etwanne est plus rapide avec un très grand nombre de noms. A vérifier.

                                      Après tout dépend ce que tu veux, en terme de performance pure, à moins que tu es vraiment beaucoup de noms à gérer, la différence ne devrait pas trop se faire sentir.

                                      -
                                      Edité par Jevanni 20 mai 2015 à 11:17:18

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        20 mai 2015 à 12:08:35

                                        Merci pour le complément d'info entwanne :)

                                        "C'est quoi la différence entre la solution de Jevanni et celle de Olygrim/entwanne concrètement ? est elle plus performante ?"

                                        La différence principale est la qualité de lecture (point super important en python). Après en terme de performance, j'aurai tendance à dire qu'on s'en fout un peu. A moins que tu es beaucoup d'éléments dans ta liste, le temps de traitement ne doit pas vraiment être perceptible (j'ai pas testé, mais pour moi c'est secondaire pour ce cas précis).

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Précepte: Le mieux est l'ennemi du bien

                                        renommer doublons dans liste

                                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                        • Editeur
                                        • Markdown