34 votes

Trouver une structure de tuple contenant une valeur inconnue dans une liste

Dire que j'ai la liste de tuples:

list = [(1,5), (1,7), (2,3)]

Est-il possible en Python pour écrire quelque chose comme

if (1, *) in list: do things

* signifie "je ne se soucient pas de cette valeur"? Donc, nous allons vérifier si il est un tuple avec 1 à la première position et à n'importe quelle valeur sur le second.

Autant que je sache, il y a des mécanismes dans d'autres langues, mais je ne sais pas le nom de ce problème particulier. Donc, il y a un comportement similaire en Python?

P. S.: je sais que je peux utiliser interprétations de la liste ici. Je suis juste intéressé par ce mécanisme.

71voto

Martijn Pieters Points 271458

Vous pouvez utiliser la fonction any() :

 if any(t[0] == 1 for t in yourlist):
 

Ceci teste efficacement et se termine tôt si 1 se trouve en première position d'un tuple.

33voto

acdr Points 1501

Un espace réservé à l'objet, comme vous me demandez n'est pas pris en charge nativement, mais vous pouvez faire quelque chose comme ça de vous-même:

class Any(object):
    def __eq__(self, other):
        return True
ANYTHING = Any()

lst = [(1,5), (1,7), (2,3)]

L' __eq__ méthode définit la façon dont les deux objets de test pour l'égalité. (Voir https://docs.python.org/3/reference/datamodel.html pour plus de détails.) Ici, ANYTHING sera toujours le test est positif pour l'égalité avec n'importe quel objet. (À moins que l'objet de aussi surpassé __eq__ dans une sorte de Fausse déclaration.)

L' in opérateur appelle simplement __eq__ pour chaque élément de votre liste. I. e. a in b fait quelque chose comme:

for elem in b:
    if elem == a:
        return True

Cela signifie que, si vous dites (1, ANYTHING) in lst, Python va d'abord comparer (1, ANYTHING) pour le premier élément, en lst. (Tuples, à son tour, définissent __eq__ retourner True si tous ses éléments" __eq__ return True. I. e. (x, y) == (a, b) est équivalent à x==a and y==bou x.__eq__(a) and y.__eq__(b).)

Par conséquent, (1, ANYTHING) in lst renvoie True, alors qu' (3, ANYTHING) in lst retournera False.

Notez également que j'ai renommé votre liste lst au lieu de list pour éviter les collisions de noms avec le Python-en list.

10voto

Eddo Hintoso Points 372

Pas tous mes méthodes de solution fournie ci-dessous sera nécessairement efficace. Mon but est de montrer toutes les solutions possibles de la méthode que je pense - à la fin de ma réponse je fournir "de référence", les résultats de montrer pourquoi ou pourquoi pas, vous devez utiliser une certaine méthode plutôt qu'une autre. Je crois que c'est un bon moyen d'apprendre, et je vais sans vergogne encourager un tel apprentissage dans mes réponses.


Sous-ensemble + de hachage sets

>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> set([l[0] for l in a_list])
{1, 2}
>>>
>>> 1 in set([l[0] for l in a_list])
True

map(), et les fonctions anonymes

>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> map(lambda x: x[0] == 1, a_list)
[True, True, False]
>>>
>>> True in set(map(lambda x: x[0] == 1, a_list))
True

filter et les fonctions anonymes

>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> filter(lambda x: x[0] == 1, a_list)
[(1,5), (1,7)]
>>>
>>> len(filter(lambda x: x[0] == 1, a_list)) > 0  # non-empty list
True

MICROBENCHMARKS

Conditions

  • 1000 articles
  • 100K répétition
  • 0-100 gamme hasard
  • Python 2.7.10, IPython 2.3.0

Script

from pprint import pprint
from random import randint
from timeit import timeit

N_ITEMS = 1000
N_SIM = 1 * (10 ** 5)  # 100K = 100000

a_list = [(randint(0, 100), randint(0, 100)) for _ in range(N_ITEMS)]

set_membership_list_comprehension_time = timeit(
    "1 in set([l[0] for l in a_list])",
    number = N_SIM,
    setup="from __main__ import a_list"
)

bool_membership_map_time = timeit(
    "True in set(map(lambda x: x[0] == 1, a_list))",
    number = N_SIM,
    setup="from __main__ import a_list"
)

nonzero_length_filter_time = timeit(
    "len(filter(lambda x: x[0] == 1, a_list)) > 0",
    number = N_SIM,
    setup="from __main__ import a_list"
)

any_list_comprehension_time = timeit(
    "any(t[0] == 1 for t in a_list)",
    number = N_SIM,
    setup="from __main__ import a_list"
)

results = {
    "any(t[0] == 1 for t in a_list)": any_list_comprehension_time,
    "len(filter(lambda x: x[0] == 1, a_list)) > 0": nonzero_length_filter_time,
    "True in set(map(lambda x: x[0] == 1, a_list))": bool_membership_map_time,
    "1 in set([l[0] for l in a_list])": set_membership_list_comprehension_time
}

pprint(
    sorted(results.items(), key = lambda x: x[1])
)

Résultats (en secondes)

[('any(t[0] == 1 for t in a_list)', 2.6685791015625),     # winner - Martijn
 ('1 in set([l[0] for l in a_list])', 4.85234808921814),
 ('len(filter(lambda x: x[0] == 1, a_list)) > 0', 7.11224889755249),
 ('True in set(map(lambda x: x[0] == 1, a_list))', 10.343087911605835)]

Qui a eu le dernier rire maintenant? ... Martijn (au moins j'ai essayé)

MORALE DE L'HISTOIRE: Ne pas dépenser plus de 10 minutes de "prouver" votre inférieurs solution est plus rapide et plus efficace sur un petit test de données, lors d'un autre utilisateur est la réponse de facto correct

5voto

nsr Points 120

Cela peut être fait en Python en utilisant la compréhension par liste. ex:

 a= [(1, 2), (3, 4), (4, 5), (1, 4)]
[i for i in a if i[0] == 1]
 

Te donnera:

 [(1, 2), (1, 4)]
 

3voto

Padraic Cunningham Points 87411

L'indexation est la méthode la plus simple, mais si vous souhaitez utiliser une syntaxe similaire à celle de votre exemple, où vous souhaitez affecter la première valeur à une variable et ignorer le reste, vous pouvez utiliser la décompression itérative étendue de python3.

 In [3]: [a for a,*_ in l]
Out[3]: [1, 1, 2]
 

Ou avec n'importe quelle logique:

 In [4]: l = [(1,5), (1,7), (2,3)]

In [5]: any(a == 1 for a,*_ in l)
Out[5]: True
 

Ou imiter tout sans l'appel de fonction:

 In [23]: l = [(1,5), (1,7), (2,3)]
In [24]: g = (a  for a,*_ in l)

In [25]: 1 in g
Out[25]: True

In [26]: list(g)
Out[26]: [1, 2]
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X