Python Language
Recherche
Recherche…
Remarques
Tous les algorithmes de recherche sur les itérables contenant n
éléments ont une complexité O(n)
. Seuls les algorithmes spécialisés comme bisect.bisect_left()
peuvent être plus rapides avec la complexité O(log(n))
.
Obtenir l'index des chaînes: str.index (), str.rindex () et str.find (), str.rfind ()
String
également une méthode d' index
mais aussi des options plus avancées et le str.find
supplémentaire. Pour les deux, il existe une méthode inversée complémentaire.
astring = 'Hello on StackOverflow'
astring.index('o') # 4
astring.rindex('o') # 20
astring.find('o') # 4
astring.rfind('o') # 20
La différence entre index
/ rindex
et find
/ rfind
est ce qui arrive si la sous-chaîne n'est pas trouvée dans la chaîne:
astring.index('q') # ValueError: substring not found
astring.find('q') # -1
Toutes ces méthodes permettent un index de début et de fin:
astring.index('o', 5) # 6
astring.index('o', 6) # 6 - start is inclusive
astring.index('o', 5, 7) # 6
astring.index('o', 5, 6) # - end is not inclusive
ValueError: sous-chaîne introuvable
astring.rindex('o', 20) # 20
astring.rindex('o', 19) # 20 - still from left to right
astring.rindex('o', 4, 7) # 6
Recherche d'un élément
Toutes les collections intégrées dans Python implémentent un moyen de vérifier l'appartenance à un élément en utilisant in
.
liste
alist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
5 in alist # True
10 in alist # False
Tuple
atuple = ('0', '1', '2', '3', '4')
4 in atuple # False
'4' in atuple # True
Chaîne
astring = 'i am a string'
'a' in astring # True
'am' in astring # True
'I' in astring # False
Ensemble
aset = {(10, 10), (20, 20), (30, 30)}
(10, 10) in aset # True
10 in aset # False
Dict
dict
est un peu spécial: la normale in
vérifie que les clés. Si vous souhaitez rechercher des valeurs, vous devez le spécifier. La même chose si vous souhaitez rechercher des paires clé-valeur .
adict = {0: 'a', 1: 'b', 2: 'c', 3: 'd'}
1 in adict # True - implicitly searches in keys
'a' in adict # False
2 in adict.keys() # True - explicitly searches in keys
'a' in adict.values() # True - explicitly searches in values
(0, 'a') in adict.items() # True - explicitly searches key/value pairs
Obtenir la liste d'index et les tuples: list.index (), tuple.index ()
list
et tuple
ont une méthode d' index
pour obtenir la position de l'élément:
alist = [10, 16, 26, 5, 2, 19, 105, 26]
# search for 16 in the list
alist.index(16) # 1
alist[1] # 16
alist.index(15)
ValueError: 15 n'est pas dans la liste
Mais ne retourne que la position du premier élément trouvé:
atuple = (10, 16, 26, 5, 2, 19, 105, 26)
atuple.index(26) # 2
atuple[2] # 26
atuple[7] # 26 - is also 26!
Recherche de clé (s) pour une valeur dans dict
dict
n'ont pas de méthode intégrée pour rechercher une valeur ou une clé car les dictionnaires ne sont pas ordonnés. Vous pouvez créer une fonction qui obtient la clé (ou les clés) pour une valeur spécifiée:
def getKeysForValue(dictionary, value):
foundkeys = []
for keys in dictionary:
if dictionary[key] == value:
foundkeys.append(key)
return foundkeys
Cela pourrait également être écrit comme une liste de compréhension équivalente:
def getKeysForValueComp(dictionary, value):
return [key for key in dictionary if dictionary[key] == value]
Si vous ne vous souciez que d'une clé trouvée:
def getOneKeyForValue(dictionary, value):
return next(key for key in dictionary if dictionary[key] == value)
Les deux premières fonctions renverront une list
de toutes les keys
ayant la valeur spécifiée:
adict = {'a': 10, 'b': 20, 'c': 10}
getKeysForValue(adict, 10) # ['c', 'a'] - order is random could as well be ['a', 'c']
getKeysForValueComp(adict, 10) # ['c', 'a'] - dito
getKeysForValueComp(adict, 20) # ['b']
getKeysForValueComp(adict, 25) # []
L'autre ne renverra qu'une clé:
getOneKeyForValue(adict, 10) # 'c' - depending on the circumstances this could also be 'a'
getOneKeyForValue(adict, 20) # 'b'
et StopIteration
une StopIteration
- Exception
si la valeur n'est pas dans le dict
:
getOneKeyForValue(adict, 25)
StopIteration
Obtenir l'index des séquences triées: bisect.bisect_left ()
Les séquences triées permettent l'utilisation d'algorithmes de recherche plus rapides: bisect.bisect_left()
1 :
import bisect
def index_sorted(sorted_seq, value):
"""Locate the leftmost value exactly equal to x or raise a ValueError"""
i = bisect.bisect_left(sorted_seq, value)
if i != len(sorted_seq) and sorted_seq[i] == value:
return i
raise ValueError
alist = [i for i in range(1, 100000, 3)] # Sorted list from 1 to 100000 with step 3
index_sorted(alist, 97285) # 32428
index_sorted(alist, 4) # 1
index_sorted(alist, 97286)
ValeurErreur
Pour les très grandes séquences triées, le gain de vitesse peut être assez élevé. Pour la première recherche, environ 500 fois plus rapidement:
%timeit index_sorted(alist, 97285)
# 100000 loops, best of 3: 3 µs per loop
%timeit alist.index(97285)
# 1000 loops, best of 3: 1.58 ms per loop
Bien que ce soit un peu plus lent si l'élément est l'un des tous premiers:
%timeit index_sorted(alist, 4)
# 100000 loops, best of 3: 2.98 µs per loop
%timeit alist.index(4)
# 1000000 loops, best of 3: 580 ns per loop
Recherche de séquences imbriquées
La recherche dans des séquences imbriquées comme une list
de tuple
nécessite une approche telle que la recherche de clés dans les dict
mais nécessite des fonctions personnalisées.
L'index de la séquence la plus externe si la valeur a été trouvée dans la séquence:
def outer_index(nested_sequence, value):
return next(index for index, inner in enumerate(nested_sequence)
for item in inner
if item == value)
alist_of_tuples = [(4, 5, 6), (3, 1, 'a'), (7, 0, 4.3)]
outer_index(alist_of_tuples, 'a') # 1
outer_index(alist_of_tuples, 4.3) # 2
ou l'index de la séquence externe et interne:
def outer_inner_index(nested_sequence, value):
return next((oindex, iindex) for oindex, inner in enumerate(nested_sequence)
for iindex, item in enumerate(inner)
if item == value)
outer_inner_index(alist_of_tuples, 'a') # (1, 2)
alist_of_tuples[1][2] # 'a'
outer_inner_index(alist_of_tuples, 7) # (2, 0)
alist_of_tuples[2][0] # 7
En général ( pas toujours ) utiliser next
et une expression de générateur avec des conditions pour trouver la première occurrence de la valeur recherchée est l'approche la plus efficace.
Recherche dans des classes personnalisées: __contains__ et __iter__
Pour autoriser l'utilisation de in
pour les classes personnalisées, la classe doit fournir la méthode magique __contains__
ou, à défaut, une __iter__
__iter__.
Supposons que vous ayez une classe contenant une list
de list
s:
class ListList:
def __init__(self, value):
self.value = value
# Create a set of all values for fast access
self.setofvalues = set(item for sublist in self.value for item in sublist)
def __iter__(self):
print('Using __iter__.')
# A generator over all sublist elements
return (item for sublist in self.value for item in sublist)
def __contains__(self, value):
print('Using __contains__.')
# Just lookup if the value is in the set
return value in self.setofvalues
# Even without the set you could use the iter method for the contains-check:
# return any(item == value for item in iter(self))
L'utilisation du test d'appartenance est possible en utilisant in
:
a = ListList([[1,1,1],[0,1,1],[1,5,1]])
10 in a # False
# Prints: Using __contains__.
5 in a # True
# Prints: Using __contains__.
même après la suppression de la méthode __contains__
:
del ListList.__contains__
5 in a # True
# Prints: Using __iter__.
Remarque: La boucle in
(comme for i in a
) utilisera toujours __iter__
même si la classe implémente une __contains__
méthode.