web-dev-qa-db-fra.com

Python: recherche la chaîne la plus proche (d'une liste) vers une autre chaîne

Disons que j'ai un string"Hello" et une liste

words = ['hello', 'Hallo', 'hi', 'house', 'key', 'screen', 'hallo','question', 'Hallo', 'format']

Comment trouver les n words qui sont les plus proches de "Hello" et présents dans la liste words?

Dans ce cas, nous aurions ['hello', 'hallo', 'Hallo', 'hi', 'format'...]

La stratégie consiste donc à trier les mots de la liste du mot le plus proche au mot le plus éloigné.

J'ai pensé à quelque chose comme ça

Word = 'Hello'
for i, item in enumerate(words):
    if lower(item) > lower(Word):
      ...

mais c'est très lent dans les grandes listes.

UPDATEdifflib fonctionne mais il est également très lent. (words list contient plus de 630000 mots (triés et un par ligne)). La vérification de la liste prend donc 5 à 7 secondes pour chaque recherche du mot le plus proche!

41
Laura

Utilisez difflib.get_close_matches .

>>> words = ['hello', 'Hallo', 'hi', 'house', 'key', 'screen', 'hallo', 'question', 'format']
>>> difflib.get_close_matches('Hello', words)
['hello', 'Hallo', 'hallo']

Veuillez consulter la documentation, car la fonction renvoie par défaut 3 correspondances les plus proches ou moins.

68
Oleh Prypin

Il existe un article génial avec un code source complet (21 lignes) fourni par Peter Norvig sur la correction orthographique. 

http://norvig.com/spell-correct.html

L’idée est de construire toutes les modifications possibles de votre Word,

hello - helo   - deletes    
hello - helol  - transpose    
hello - hallo  - replaces    
hello - heallo - inserts    


def edits1(Word):
   splits     = [(Word[:i], Word[i:]) for i in range(len(Word) + 1)]
   deletes    = [a + b[1:] for a, b in splits if b]
   transposes = [a + b[1] + b[0] + b[2:] for a, b in splits if len(b)>1]
   replaces   = [a + c + b[1:] for a, b in splits for c in alphabet if b]
   inserts    = [a + c + b     for a, b in splits for c in alphabet]
   return set(deletes + transposes + replaces + inserts)

Maintenant, recherchez chacune de ces modifications dans votre liste. 

L'article de Peter est une excellente lecture et mérite d'être lu.

21
Amjith

Créez une liste triée de vos mots et utilisez le module bisect - pour identifier le point de la liste triée où votre mot-clé s’adapterait en fonction de l’ordre de tri. En fonction de cette position, vous pouvez donner aux k voisins les plus proches situés au-dessus et au-dessous pour trouver les 2k mots les plus proches. 

1
user1308520

peut-être que heap peut vous aider. 

vous avez un tas nommé Heap qui jusqu'à ce que sa taille soit inférieure à n, vous insérez des mots dans Heap en utilisant la fonction close [montre que cette chaîne est plus proche qu'une autre chaîne ou non].

cette méthode peut vous aider lorsque n est petit :)

Heap = []
for Word in words:
    if len(Heap)<n:
       Heap.insert(Word)
    else
       if close(Word,Heap[0]): # it means Heap[0] is the nth farthest Word until now
             Heap.pop():
             Heap.insert(Word)
0
Divuneh