Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comparaison de liste

Sujet résolu
    16 mars 2021 à 9:28:03

    Bonjour,

    J'apprends le python en autodidacte et parfois il me manquerait un professeur pour des choses qui doivent être basiques, là je bute sur un truc qui doit pas être foufou:

    Comment comparer l'élément d'une liste au suivant sans avoir un index out of range?

    Je comprends bien d'où vient le problème avec le dernier élément de la liste qui n'a pas de suivant, mais je ne sais pas comment feinter.

    Par exemple avec ce code:

    for i, e in enumerate(items):
    if e == items[i+1]:
    items.pop(i)

    Merci d'avance :)

    -
    Edité par AlexAlexs 16 mars 2021 à 9:39:10

    • Partager sur Facebook
    • Partager sur Twitter
      16 mars 2021 à 9:42:55

      Salut,

      Tu pourrai vérifier que ton i+1 ne soit pas supérieur a la taille de ta liste

      • Partager sur Facebook
      • Partager sur Twitter
        16 mars 2021 à 9:56:56

        Ah ben oui forcement... ça fonctionne merci :)
        • Partager sur Facebook
        • Partager sur Twitter
          16 mars 2021 à 11:07:15

          Bonjour,

          Si tu veux enlever les doublons:

          >>> items = [1, 2, 2, 3, 4, 5, 5, 5]
          >>> items = list(set(items))
          >>> items
          [1, 2, 3, 4, 5]
          

          Si tu souhaites comparer :

          >>> items = [1, 2, 2, 3, 4, 5, 5, 5]
          >>> for index in range(1,len(items)):
          ...     if items[index-1] == items[index]:
          ...             print(items[index]) 
          ... 
          2
          5
          5
          >>> 
          

          édit:

          à noter que tu ne peux pas utiliser pop(index) sur une liste que tu parcoures avec for (because les index changeraient au fur et à mesure)


          -
          Edité par __fabien 16 mars 2021 à 11:18:36

          • Partager sur Facebook
          • Partager sur Twitter
          • J'aime les bananes, le python, le gnu, le pingouin.
            • Vive le libre !
            16 mars 2021 à 12:03:25

            Merci beaucoup.

            Au lieu de pop, je passe par une seconde liste sur laquelle je *.append(x) les éléments à conserver du coup.

            Je ne sais pas si c'est optimal mais bon... ça semble fonctionner.

            Si y a mieux je suis preneur, ce genre de détails manquent quand on apprend seul. Parfois j'écris 20 lignes et je vois que ça pourrait n'en prendre qu'une.

            -
            Edité par AlexAlexs 16 mars 2021 à 12:03:37

            • Partager sur Facebook
            • Partager sur Twitter
              16 mars 2021 à 17:28:13

              AlexAlexs a écrit:

              Comment comparer l'élément d'une liste au suivant sans avoir un index out of range?

              for i, e in enumerate(items):
              if e == items[i+1]:
              items.pop(i)

              Le problème est que tu utilises enumerate sur lequel tu n'as aucun contrôle. Lorsque tu veux parcourir une liste (ou une séquence) avec des conditions portant sur des valeurs de la liste en fonction des indices (du genre l'indice suivant, l'indice précédent, le deuxième indice, l'avant-dernier indice, etc), il est bien plus simple d'utiliser un range approprié. Typiquement, pour savoir si une liste est croissante, tu peux écrire :

              def estCroissante(L):
                  for i in range(len(L)-1):
                      if L[i+1]<L[i]:
                          return False
                  return True
              
              L=[42, 47, 53]
              
              print(estCroissante(L))


              C'est considéré comme peu pythonnique et c'est plus lent qu'un code qui évite d'accéder à l'élément de la liste avec le crochet. Mais si tu débutes, c'est la solution à envisager.

              • Partager sur Facebook
              • Partager sur Twitter
                16 mars 2021 à 18:02:49

                Est-ce plus Pythonique comme ceci?
                L = [1, 2, 3, 3, 4, 5]
                if all([a<=b for a,b in zip(L[:-1], L[1:])]):
                     print("en ordre")
                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  16 mars 2021 à 18:29:07

                  @PierrotLeFou:

                  Pas besoin de créer une liste --> all(a<=b for a,b in zip(L[:-1], L[1:]))

                  Ceci dit, il y a beaucoup plus simple:

                  if L == sorted(L):
                  	print("en ordre")



                  • Partager sur Facebook
                  • Partager sur Twitter
                  • J'aime les bananes, le python, le gnu, le pingouin.
                    • Vive le libre !
                    16 mars 2021 à 18:36:48

                    Peut-être mais algorithmiquement inefficace puisque chacun des slices effectue un parcours des listes (et même une copie des références) ce qui entraîne trois parcours au total. Et le temps n'est pas extraordinaire, je pensais que ça aurait mieux, c'est très comparable au temps du code que j'ai donné (qui est lent à cause des appels à __getitem__). Ci-dessous d'autres approches :

                    def estCroissante0(L):
                        for i in range(len(L)-1):
                            if L[i+1]<L[i]:
                                return False
                        return True
                    
                    def estCroissante1(L):
                        it=iter(L)
                        next(it)
                        for (a, b) in zip(L, it):
                            if a>b:
                                return False
                        return True
                    
                    def estCroissante2(L):
                        it=iter(L)
                        next(it)
                        for i, z in enumerate(it):
                            if L[i]>z:
                                return False
                        return True
                    
                    
                    def estCroissante3(L):
                        return all([a<=b for a,b in zip(L[:-1], L[1:])])
                    
                    L=list(range(5*10**6))
                    
                    
                    from time import perf_counter
                    
                    begin_perf = perf_counter()
                    
                    
                    print(estCroissante0(L))
                    
                    delta = perf_counter() - begin_perf
                    
                    print(f"Temps d'exécution : {delta:.2f}s")
                    
                    
                    begin_perf = perf_counter()
                    
                    
                    print(estCroissante1(L))
                    
                    delta = perf_counter() - begin_perf
                    
                    print(f"Temps d'exécution : {delta:.2f}s")
                    
                    
                    begin_perf = perf_counter()
                    
                    
                    print(estCroissante2(L))
                    
                    delta = perf_counter() - begin_perf
                    
                    print(f"Temps d'exécution : {delta:.2f}s")
                    
                    
                    
                    
                    
                    begin_perf = perf_counter()
                    
                    
                    print(estCroissante3(L))
                    
                    delta = perf_counter() - begin_perf
                    
                    print(f"Temps d'exécution : {delta:.2f}s")
                    True                                                                                                                                                                       
                    Temps d'exécution : 0.36s                                                                                                                                                  
                    True                                                                                                                                                                       
                    Temps d'exécution : 0.16s                                                                                                                                                  
                    True                                                                                                                                                                       
                    Temps d'exécution : 0.27s                                                                                                                                                  
                    True                                                                                                                                                                       
                    Temps d'exécution : 0.34s 


                    EDIT Oui, utiliser sorted est plus rapide si la liste est croissante mais peut être beaucoup plus lent si la liste n'est pas croissante, imaginer une liste de 10 millions d'entiers commençant par 1, 0.

                    -
                    Edité par PascalOrtiz 16 mars 2021 à 18:42:42

                    • Partager sur Facebook
                    • Partager sur Twitter
                      16 mars 2021 à 18:42:28

                      ... et ma proposition que donne t'elle?
                      • Partager sur Facebook
                      • Partager sur Twitter
                      • J'aime les bananes, le python, le gnu, le pingouin.
                        • Vive le libre !
                        16 mars 2021 à 18:45:51

                        __fabien a écrit:

                        ... et ma proposition que donne t'elle?


                        Pour sorted, j'ai ré-edité. Pour le générateur au lieu de la liste, ça ne change rien je crois, voire c'est pire, bizarrement.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          16 mars 2021 à 18:59:40

                          merci. J'ai toujours pensé que d'utiliser un générateur à la place d'une liste était plus rapide.

                          Faut croire que non.

                          • Partager sur Facebook
                          • Partager sur Twitter
                          • J'aime les bananes, le python, le gnu, le pingouin.
                            • Vive le libre !
                            16 mars 2021 à 20:57:31


                            __fabien a écrit:

                            merci. J'ai toujours pensé que d'utiliser un générateur à la place d'une liste était plus rapide.


                            Moi aussi :)

                            Pourtant :

                            from time import perf_counter
                            
                            def f(L):
                                return all([a<=b for a,b in zip(L[:-1], L[1:])])
                            
                            def g(L):
                                return all(a<=b for a,b in zip(L[:-1], L[1:]))
                            
                            L=list(range(10**7))
                            
                            begin_perf = perf_counter()
                            f(L)
                            
                            delta = perf_counter() - begin_perf
                            
                            print(f"Temps d'exécution : {delta:.2f}s")
                            
                            
                            begin_perf = perf_counter()
                            g(L)
                            
                            delta = perf_counter() - begin_perf
                            
                            print(f"Temps d'exécution : {delta:.2f}s")
                            Temps d'exécution : 0.64s
                            Temps d'exécution : 0.75s
                            


                            • Partager sur Facebook
                            • Partager sur Twitter
                              16 mars 2021 à 22:17:44

                              J'imagine que cela est dû à la façon dont all() est implanté dans python.

                              from time import perf_counter
                               
                              def f():
                                  for i in [j for j in range(10**7)]:
                                      pass
                               
                              def g():
                                  for i in (j for j in range(10**7)):
                                      pass
                              
                               
                              begin_perf = perf_counter()
                              f()
                              delta = perf_counter() - begin_perf
                              print(f"Temps d'exécution : {delta:.2f}s")
                               
                               
                              begin_perf = perf_counter()
                              g()
                              delta = perf_counter() - begin_perf
                              print(f"Temps d'exécution : {delta:.2f}s")
                              Temps d'exécution : 0.63s
                              Temps d'exécution : 0.48s

                              édit : non ce n'est pas all() qui est en cause , je viens de le vérifier.

                              Ni zip() à priori...

                              -
                              Edité par __fabien 16 mars 2021 à 22:57:43

                              • Partager sur Facebook
                              • Partager sur Twitter
                              • J'aime les bananes, le python, le gnu, le pingouin.
                                • Vive le libre !
                                17 mars 2021 à 0:31:29

                                @__fabien:
                                J'ai encore de la difficulté avec ça. Je prend note.
                                Pour le  if L == sorted(L)  c'est fort. :)
                                • Partager sur Facebook
                                • Partager sur Twitter

                                Le Tout est souvent plus grand que la somme de ses parties.

                                  11 avril 2021 à 12:59:02

                                  __fabien a écrit:

                                  merci. J'ai toujours pensé que d'utiliser un générateur à la place d'une liste était plus rapide.

                                  Faut croire que non.


                                  C'est aussi ce qui se dit, voir par exemple :

                                  Mais comme souvent, ça dépend de quoi on parle :

                                  from time import perf_counter
                                  
                                  n=5*10**7
                                  
                                  L=[10*x for x in range(n)]
                                  
                                  begin_perf = perf_counter()
                                  
                                  s0=sum(L)
                                  
                                  delta = perf_counter() - begin_perf
                                  
                                  print(f"list : {delta:.2f}s")
                                  
                                  begin_perf = perf_counter()
                                  
                                  s1=sum([10*x for x in range(n)])
                                  
                                  delta = perf_counter() - begin_perf
                                  
                                  print(f"list comp: {delta:.2f}s")
                                  
                                  begin_perf = perf_counter()
                                  
                                  s2=sum(10*x for x in range(n))
                                  
                                  delta = perf_counter() - begin_perf
                                  
                                  print(f"gene : {delta:.2f}s")
                                  
                                  begin_perf = perf_counter()
                                  G=(z for z in L)
                                  
                                  s3=sum(G)
                                  
                                  delta = perf_counter() - begin_perf
                                  
                                  print(f"gene var : {delta:.2f}s")
                                  
                                  
                                  print(s0==s1 == s2 == s3)
                                  
                                  list : 0.20s
                                  list comp: 3.01s
                                  gene : 2.94s
                                  gene var : 1.39s
                                  True
                                  










                                  -
                                  Edité par PascalOrtiz 11 avril 2021 à 13:38:22

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    12 avril 2021 à 8:41:19

                                    Merci pour ton retour :)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    • J'aime les bananes, le python, le gnu, le pingouin.
                                      • Vive le libre !

                                    Comparaison de 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