J'ai donc une liste:

my_list1 = ["p1", "p2", "p4", "p1"]

Et j'ai une autre liste avec des sous-listes:

my_list2 = [[1,"p1"], [1,"p2"], [1,"p3"], [1,"p4"], [2, "p1"], [2, "p2"], [2, "p3"], [2, "p4"]]

Maintenant, ce que je veux faire est le suivant: Je veux parcourir my_list1 puis my_list2 et créer une nouvelle liste qui contient la prochaine occurrence de chaque élément de my_list1 dans my_list2.

C'est à dire. ce que je veux obtenir c'est:

new_list = [[1, "p1"], [1, "p2"], [1, "p4"], [2, "p1"]]

J'ai déjà essayé ce qui suit:

    new_list = []
    for i in my_list1:
        for j in my_list2:
            if i in j[1]:
                new_list.append(j)

Ce qui me donne

new_list = [[1,"p1"], [1,"p2"], [1,"p4"], [2, "p1"], [2, "p2"],  [2, "p4"]]

Donc, encore une fois, ce dont j'ai besoin, c'est que chaque itération ajoute SEULEMENT LA PROCHAINE occurrence d'un élément dans my_list2.

Je suis nouveau sur Python, alors soyez gentil. Je suis très reconnaissant pour toutes suggestions!

1
Benjamin Pichl 11 avril 2018 à 17:29

4 réponses

Meilleure réponse

Il y a quelques problèmes avec votre code, mais la logique est fondamentalement correcte. Il vous suffit de faire 2 choses différemment:

1) Sortez de la boucle lorsque vous ajoutez.

2) Supprimez l'élément qui a été ajouté (afin de ne pas l'ajouter à nouveau plus tard)

Voici une approche que vous pouvez adopter:

# create a copy of my_list2 because calling pop will mutate the list
temp_list2 = [x for x in my_list2]

new_list = []
for i,x in enumerate(my_list1):
    for j,y in enumerate(temp_list2):
        if x == y[1]:
            new_list.append(temp_list2.pop(j))
            break
print(new_list)
#[[1, 'p1'], [1, 'p2'], [1, 'p4'], [2, 'p1']]

N'utilisez pas non plus in pour comparer les valeurs, utilisez plutôt ==.


Voici une approche alternative plus efficace utilisant collections.Counter:

from collections import Counter
list1_counter = Counter(my_list1)

new_list = []
for (value, key) in my_list2:
    if key in list1_counter and list1_counter[key] > 0:
        new_list.append([value, key])
        list1_counter[key] -= 1
print(new_list)
#[[1, 'p1'], [1, 'p2'], [1, 'p4'], [2, 'p1']]

Vous créez un Counter pour compter l'occurrence de chaque "clé" dans my_list1. Ensuite, vous parcourez my_list2 et vérifiez si la clé existe dans le compteur et si le nombre est supérieur à 0. Si c'est le cas, ajoutez l'élément à la liste et diminuez le compteur.

3
pault 11 avril 2018 à 14:57

Essaye ça:

new_list = []
tmp_list = my_list2.copy() #only to preserve my_list2
    for i in my_list1:
        index = 0
        for j in tmp_list :
            if i in j[1]:
                new_list.append(tmp_list.pop(index))
                break
            index += 1
1
Alekos 11 avril 2018 à 14:44

N'est-ce pas un peu simple pour vous, vous l'avez arrêté une étape plus tôt.

my_list1 = ["p1", "p2", "p4", "p1"]
my_list2 = [[1,"p1"], [1,"p2"], [1,"p3"], [1,"p4"], [2, "p1"], [2, "p2"], [2, "p3"], [2, "p4"]]
choice = 0
final_list = []
list_1_length = len(my_list1)
for each_element in my_list2:
    if each_element[1] == my_list1[choice]:
       final_list.append(each_element)
       choice += 1
       if choice == list_1_length:
          break
0
Kenstars 11 avril 2018 à 14:46

Vous pouvez utiliser collections.defaultdict pour regrouper les éléments dans my_list2 par deuxième élément, puis consommez-les pendant l'itération sur my_list1:

>>> from collections import defaultdict, deque
>>> d = defaultdict(deque)
>>> for elem in my_list2:
...     d[elem[1]].append(elem)
>>> [d[elem].popleft() for elem in my_list1]
[[1, 'p1'], [1, 'p2'], [1, 'p4'], [2, 'p1']]

Utilisation d'un deque au lieu d'un {{ X1}} permet des pops efficaces du côté gauche.

2
Eugene Yarmash 11 avril 2018 à 14:56