2
votes

Filtrer une liste de paires (tuples) où le tuple n'inclut aucune valeur d'une autre liste

J'ai une liste de tuples:

[p for p in my_list if p[0] not in [v[0] for v in reference_list] and p[1] not in [v[0] for v in reference_list]]

et une liste de valeurs que je veux exclure qui sont au format:

[(5,6),(7,8)] 

La valeur que je souhaite exclure est la première de la paire. (La signification des 20, 46, 918 n'est pas importante)

Je voudrais donc renvoyer une liste de tuples qui n'incluent aucune des valeurs 2,3, 4. p >

Résultat attendu:

reference_list = [(2,20),(3,46),(4,918)] 

(car tous les autres contiennent une ou plusieurs des valeurs 2, 3 ou 4)

Ce que je ' J'ai essayé:

my_list = [(1,2),(2,3),(3,4),(4,5),(5,6),(7,8)]

Je recherche la première ou la deuxième valeur de la paire ne figurant pas dans la liste v [0] de la liste de référence.

Cela fonctionne mais je recherche une manière plus concise / pythonique, le cas échéant. Idéalement extensible (sans simplement ajouter des conditions comme p [2] pas dans la liste et p [3] pas dans la liste et.


0 commentaires

3 Réponses :


3
votes

Flat vaut mieux que nested

[p for p in my_list if not any(el in blacklist for el in p)]

Cela ne résout pas le cas généralisé, mais vous pouvez le faire avec un tiret de any :

blacklist = {p[0] for p in blacklist_of_tuples}
[p for p in my_list if p[0] not in blacklist and p[1] not in blacklist]


0 commentaires

2
votes

Utilisez une liste-compréhension avec any () code > :

lst1 = [(1,2),(2,3),(3,4),(4,5),(5,6),(7,8)]
lst2 = [(2,20),(3,46),(4,918)] 

set_lst2 = set(lst2)
print([x for x in lst1 if not any(y[0] in x for y in set_lst2)])
# [(5, 6), (7, 8)]

Code :

[x for x in lst1 if not any(y[0] in x for y in lst2)]


4 commentaires

La conversion en set ralentit en fait les choses ici: premièrement, vous utilisez l'ensemble pour l'itération au lieu de la vérification d'appartenance, ce qui est beaucoup plus lent que d'utiliser une liste. De plus, vous reconstruisez un ensemble à chaque itération.


@ Tomothy32, set est plus rapide dans les cas où il y a plusieurs doublons dans la deuxième liste, mais je suis d'accord sur la reconstruction à chaque itération. Correction de ça.


Je déteste être pédant ici, mais le coût d'itération sur un ensemble est beaucoup plus élevé que le coût de quelques itérations supplémentaires (à moins, bien sûr, que la liste soit principalement composée de doublons). Quoi qu'il en soit, belle réponse, je vais vous laisser un vote favorable. :)


@ Tomothy32, oh! ya. Vous parliez de la vérification d'adhésion est plus rapide que l'ensemble pour l'itération (+1). Je ferais mieux de laisser cela tel qu'il est déjà car la même chose est couverte dans une autre réponse. :)



1
votes

Pour des raisons de performances pour des listes plus volumineuses, vous devez créer un ensemble contenant les premiers éléments de la deuxième liste:

%timeit [t for t in list_a if not set_b.intersection(t)]
2.7 µs ± 377 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit [t for t in list_a if not any(el in set_b for el in t)]
4.97 µs ± 479 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

En général, la méthode intersection est un peu plus rapide que any:

list_a = [(1,2),(2,3),(3,4),(4,5),(5,6),(7,8)]
list_b = [(2,20),(3,46),(4,918)]

set_b = {t[0] for t in list_b}

result = [t for t in list_a if not set_b.intersection(t)]


0 commentaires