Partage
  • Partager sur Facebook
  • Partager sur Twitter

Deplacer des elements d'une liste

bouger de x places vers le debut ou la fin d'une liste

    3 janvier 2016 à 14:23:57

    Bonjour, 

    je souhaite deplacer des elements dans une liste, et je voudrai savoir quelle est la meilleure methode pour ca. Pour l'instant, j'ai 

    def moveUpInList(inputList, target=[], iter=1):
        target = target if isinstance(target, list) else [target]
        for i, e in enumerate(inputList):
            for f in target:
                if e == f:
                    if not i==0:
                        inputList.pop(i)
                        inputList.insert(i-iter, e)
        return inputList

    du coup, si j'execute :

    l = ['0', '1', '2', '3', '4', '5']
    print l
    print moveUpInList(l, '2', 1)

    il me return bien 

    ['0', '1', '2', '3', '4', '5']

    ['0', '2', '1', '3', '4', '5']

    Mais quand j'essaye de le faire dans la direction opposee, bien sur, ca ne marche plus puisque l'ordre de mes elements est different.

    D'une part, je pense que cette methode est assez lourde, et je suis un peu bloque pour la faire fonctionner dans le sens inverse (vers le bas)

    Quelqu'un aurait deja eu a faire ca ?

    -
    Edité par fruity' 3 janvier 2016 à 14:28:00

    • Partager sur Facebook
    • Partager sur Twitter
      24 décembre 2023 à 10:39:28

      Bonjour,

      Si j'ai bien compris ta requête, tu veux déplacer une information d'une liste que ce soit d'avant ou en arrière.

      J'ai un petite idée :

      liste = ['1', '2', '3', '4', '5']
      
      def mouvement(liste, pos_de_objet_dans_liste, decalage, mode):
          objet = liste[pos_de_objet_dans_liste -1]
          del(liste[pos_de_objet_dans_liste -1])
          compte = 0
          nouvelle_liste = []
          for i in liste:
              if mode == 0:
                  if compte == (pos_de_objet_dans_liste -1 + decalage % len(liste)):
                      nouvelle_liste.append(objet)
                      nouvelle_liste.append(liste[compte])
                  else:
                      nouvelle_liste.append(liste[compte])
              else:
                  if compte == (pos_de_objet_dans_liste -1 - decalage % len(liste)):
                      nouvelle_liste.append(objet)
                      nouvelle_liste.append(liste[compte])
                  else:
                      nouvelle_liste.append(liste[compte])
              compte += 1
          return nouvelle_liste
      
      print(mouvement(liste, 2, 1, 0)) -> ['1', '3', '2', '4', '5]

      Donc quand le mode == 0, il va decaler a droite. Sinon si le mode == 1, il va decaler a gauche.

      Je suis encore débutant, donc je pense qu'on peut clairement réduire ce code, mais bon, c'est un bon début !

      • Partager sur Facebook
      • Partager sur Twitter
        24 décembre 2023 à 12:22:03

        Bonjour,

        Ou bien comme ceci:

        liste = ['0','1','2','3','4','5']
        
        element_a_deplacer = '2'
        nouvelle_position = 3
        
        position_courante = liste.index(element_a_deplacer)
        liste = liste[:position_courante]+liste[position_courante+1:]
        liste.insert(nouvelle_position, element_a_deplacer)
        
        print(liste)


        10 lignes et ca marche dans tous les sens (pas besoin de variable mode)

        -
        Edité par Phil_1857 24 décembre 2023 à 15:05:10

        • Partager sur Facebook
        • Partager sur Twitter
          3 janvier 2024 à 17:49:12

          lacourgetteenragé a écrit:

          J'ai un petite idée :

          ...
              for i in liste:
                  if mode == 0:
                      if compte == (pos_de_objet_dans_liste -1 + decalage % len(liste)):
                          nouvelle_liste.append(objet)
                          nouvelle_liste.append(liste[compte])
                      else:
                          nouvelle_liste.append(liste[compte])
                  else:
                      if compte == (pos_de_objet_dans_liste -1 - decalage % len(liste)):
                          nouvelle_liste.append(objet)
                          nouvelle_liste.append(liste[compte])
                      else:
                          nouvelle_liste.append(liste[compte])
                  compte += 1
              ...

          Donc quand le mode == 0, il va decaler a droite. Sinon si le mode == 1, il va decaler a gauche.

          Je suis encore débutant, donc je pense qu'on peut clairement réduire ce code, mais bon, c'est un bon début !


          Au moins c'est un début.  Et en effet, on peut réduire "mécaniquement" un code comme

                if compte == (pos_de_objet_dans_liste -1 + decalage % len(liste)):
                          nouvelle_liste.append(objet)
                          nouvelle_liste.append(liste[compte])
                      else:
                          nouvelle_liste.append(liste[compte])

          en remarquant que les deux branches du if se terminent par la même instruction, qu'on peut donc "factoriser" en la sortant du if

                if compte == (pos_de_objet_dans_liste -1 + decalage % len(liste)):
                          nouvelle_liste.append(objet)
                nouvelle_liste.append(liste[compte])
                

          (et le else saute, parce qu'il n'y a plus rien dedans)

          De même pour le  if suivant, qui devient

               if compte == (pos_de_objet_dans_liste -1 - decalage % len(liste)):
                          nouvelle_liste.append(objet)
               nouvelle_liste.append(liste[compte])
          

          et du coup du coup, c'est pareil pour le if mode == 0, dont les deux branches se terminent pareil et qui devient, dukou dukou

                  if mode == 0:
                      if compte == (pos_de_objet_dans_liste -1 + decalage % len(liste)):
                          nouvelle_liste.append(objet)
                   else:
                      if compte == (pos_de_objet_dans_liste -1 - decalage % len(liste)):
                          nouvelle_liste.append(objet)
                  nouvelle_liste.append(liste[compte])


          Bref, quand on voit qu'il y a du code qui se répète, au lieu de copier coller, il faut regarder comment le factoriser (code folding).

          Ca n'empêche pas bien sur de réfléchir à d'autres améliorations.

          Parce que là on voit qu'on utilise deux fois l'expression decalage % len(liste). On pourrait faire

          d = decalage % len(liste)

          et d apparaitrait dans les deux if, avec un signe différent. Mais on pourrrait changer le signe selon mode (si on y tient)

          if mode != 0:
              d = -d
          


          et comme ça il n'y aurait plus qu'un seul if

          if compte == (pos_de_objet_dans_liste - 1 + d):
                 nouvelle_liste.append(objet)
          nouvelle_liste.append(liste[compte]


          Donc

          • pliage de code
          • utilisation de variables intermédiaires pour les sous-expressions communes
          • Partager sur Facebook
          • Partager sur Twitter
            3 janvier 2024 à 18:28:11

            fruity' a écrit:

            Quelqu'un aurait deja eu a faire ca ?

            Pour permuter le i-ème élément avec son successeur:

            >>> L
            [0, 1, 2, 3, 4]
            >>> i = 2
            >>> L[i], L[i+1] = L[i+1], L[i]
            >>> L
            [0, 1, 3, 2, 4]
            

            et si on l'applique 2 fois, on retombe sur ses pattes:

            >>> L[i], L[i+1] = L[i+1], L[i]
            >>> L
            [0, 1, 2, 3, 4]
            >>>

            Après il faut mettre des tests autour pour gérer le premier et le dernier item. Et comme il semble  que vous voulez travailler sur des valeurs (et non des index/positions), il faut traiter le cas où cette valeur apparaît plusieurs fois.





            • Partager sur Facebook
            • Partager sur Twitter
              4 janvier 2024 à 7:29:32

              Bravo! Nous avons déterré un sujet vieux de 2016. Alors, je sort ma pelle.


              Je suppose que l'indice du début de l'intervalle, la longueur de l'intervalle et la valeur du décalage sont connus.

              Un décalage négatif est équivalent à un décalage positif du complément par rapport à la longueur.

              -

              def decalerDansListe(liste, debut, longueur, decalage):


                  if decalage < 0: decalage += longueur     # Si un décalage vers le début est positif.


                  #decalage = longueur - decalage if decalage > 0 else -decalage     # Si un dé calage vers la fin est positif.


                  liste[debut: debut+longueur] = liste[debut+decalage: debut+longueur] + liste[debut: debut+decalage]


                  return liste


              L = list(range(1, 7+1))


              print(decalerDansListe(L, 1, 5, 3))


              L = list(range(1, 7+1))


              print(decalerDansListe(L, 1, 5, -3))


              -


              [1, 5, 6, 2, 3, 4, 7]                                                                                                   


              [1, 4, 5, 6, 2, 3, 7]                                                                                                   

              • Partager sur Facebook
              • Partager sur Twitter

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

                4 janvier 2024 à 9:25:48

                Il faudrait aussi spécifier si l'opération doit altérer la liste existante, ou renvoyer une nouvelle liste (en laissant intacte la liste d'origine, de préférence).

                Bon, ce qui serait bien, c'est de commencer par faire un peu d'analyse du problème. On suppose qu'on a la liste ['a', 'b', 'c', 'd', 'e'] et qu'on va pas demander des trucs impossibles.

                • décaler un truc vers la droite, on fait comment ?  Disons décaler 'b' de n=2 positions vers la droite. On est d'accord qu'on se retrouvera avec ['a', 'c', 'd', 'b', 'e'] ? Sinon c'est qu'on parle pas de la même chose... Bref, 'b' qui était à l'indice 1 se retrouve à l'indice 3. Il ne vous échappe sans doute pas que 3 = 2 + 1, et on peut même se convaincre qu'en général l'indice final, c'est l'indice initial + n (le décalage voulu vers la droite)
                • vers la gauche ? on repart de la même liste, on décale 'd' (qui est à l'indice 3) de n = 2 vers la gauche, on trouve ['a', 'd', 'b', 'c', 'e'],   le 'd' est à à l'indice 1 = indice initial - n
                Si je ne me suis pas trompé, ça va pas être compliqué de faire une fonction qui travaille directement dans la liste (en la modifiant)
                • trois paramètres : la liste à modifier, la valeur à déplacer, et la décalage voulu (négatif vers la gauche)
                • un coup d'index pour trouver l'indice initial
                • un coup de remove pour retirer la valeur
                • et un insert pour le remettre au bon endroit (indice initial + décalage).

                --- EDIT

                Bon, mise en œuvre, c'est tout bête

                def decaler_dans_liste(liste, valeur, decalage):
                
                    """modifie la liste en déplaçant la première instance
                    de valeur de decalage positions vers la droite.
                    (décalage vers la gauche si négatif"""
                
                    indice = liste.index(valeur)
                    liste.pop(indice)
                    liste.insert(indice + decalage, valeur)
                

                on choisit pop parce que liste.remove(valeur), ça ferait re-parcourir la liste, alors qu'on a déjà l'indice de la valeur à déplacer.

                Bon, c'est pas tout de pondre du code magique, il faut aussi montrer que ça passe bien quelques tests. J'utilise un bête assert, les frameworks de tests, c'est pour quand on s'est totalement convaincu qu'on allait en écrire systématiquement, ce qui ne correspond pas à la réalité des débutants (hélas). Assert, c'est déjà ça...

                print("# debut des tests")
                ab = ['a', 'b']
                ba = ['b', 'a']
                verifier_decalage(ab, 'a', 1, ba)
                verifier_decalage(ab, 'b', -1, ba)
                verifier_decalage(ab, 'a', 0, ab)
                abcde = ['a','b','c','d','e']
                verifier_decalage(abcde, 'b',  2, ['a','c', 'd','b','e'])
                verifier_decalage(abcde, 'd', -2, ['a','d', 'b','c','e'])
                print("tests ok")

                La fonction vérifier_decalage, elle effectue un décalage défini par les 3 premiers paramètres, et elle regarde si le résultat est celui attendu (dernier paramètre) avec un assert.

                Important : comme la fonction modifier_decalage a pour mission de modifier la liste qui lui est transmise, vérifier_décalage travaille sur une copie pour ne pas niq*er le contenu des variables ab, ba, etc. qui servent plusieurs fois dans les tests

                def verifier_decalage(liste, valeur, decalage, resultat):
                    copy = liste[:]
                    decaler_dans_liste(copy, valeur, decalage)
                    assert copy == resultat
                




                -
                Edité par michelbillaud 5 janvier 2024 à 13:55:26

                • Partager sur Facebook
                • Partager sur Twitter

                Deplacer des elements d'une liste

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                • Editeur
                • Markdown