Si j'ai une liste de chaînes par exemple:
["car", "tree", "boy", "girl", "arc"...]
Que dois-je faire pour trouver des anagrammes dans cette liste? Par exemple, (car, arc)
. J’ai essayé d’utiliser boucle for pour chaque chaîne et j’ai utilisé if
afin d’ignorer des chaînes de longueurs différentes, mais je ne parviens pas à obtenir le bon résultat.
Comment puis-je parcourir chaque lettre de la chaîne et la comparer aux autres de la liste dans un ordre différent?
J'ai lu plusieurs questions similaires, mais les réponses étaient trop avancées. Je ne peux rien importer et je ne peux utiliser que des fonctions de base.
Pour ce faire pour 2 chaînes, vous pouvez le faire:
def isAnagram(str1, str2):
str1_list = list(str1)
str1_list.sort()
str2_list = list(str2)
str2_list.sort()
return (str1_list == str2_list)
Quant à l'itération sur la liste, c'est assez simple
Créez un dictionnaire de (Word trié, liste de Word). Tous les mots qui sont dans la même liste sont des anagrammes les uns des autres.
from collections import defaultdict
def load_words(filename='/usr/share/dict/american-english'):
with open(filename) as f:
for Word in f:
yield Word.rstrip()
def get_anagrams(source):
d = defaultdict(list)
for Word in source:
key = "".join(sorted(Word))
d[key].append(Word)
return d
def print_anagrams(Word_source):
d = get_anagrams(Word_source)
for key, anagrams in d.iteritems():
if len(anagrams) > 1:
print(key, anagrams)
Word_source = load_words()
print_anagrams(Word_source)
Ou:
Word_source = ["car", "tree", "boy", "girl", "arc"]
print_anagrams(Word_source)
Une solution consiste à trier le mot que vous recherchez avec des anagrammes (par exemple, à l'aide de sorted
), trier l'alternative et la comparer.
Donc, si vous recherchez des anagrammes de 'rac' dans la liste ['car', 'girl', 'tofu', 'rca']
, votre code pourrait ressembler à ceci:
Word = sorted('rac')
alternatives = ['car', 'girl', 'tofu', 'rca']
for alt in alternatives:
if Word == sorted(alt):
print alt
Triez chaque élément puis recherchez les doublons. Il y a une fonction intégrée pour le tri afin que vous n'ayez rien à importer
def findanagranfromlistofwords(li):
dict = {}
index=0
for i in range(0,len(li)):
originalfirst = li[index]
sortedfirst = ''.join(sorted(str(li[index])))
for j in range(index+1,len(li)):
next = ''.join(sorted(str(li[j])))
print next
if sortedfirst == next:
dict.update({originalfirst:li[j]})
print "dict = ",dict
index+=1
print dict
findanagranfromlistofwords(["car", "tree", "boy", "girl", "arc"])
Il y a plusieurs solutions à ce problème:
Approche classique
Considérons d’abord ce qui définit un anagramme: deux mots sont des anagrammes s’ils se composent du même ensemble de lettres et si chaque lettre apparaît exactement le même nombre ou la même heure dans les deux mots. Ceci est essentiellement un histogramme du nombre de lettres de chaque mot. C'est un cas d'utilisation parfait pour la structure de données collections.Counter
( voir docs ). Les algorithmes sont les suivants:
Voici le code:
from collections import Counter, defaultdict
def anagram(words):
anagrams = defaultdict(list)
for Word in words:
histogram = Tuple(Counter(Word).items()) # build a hashable histogram
anagrams[histogram].append(Word)
return list(anagrams.values())
keywords = ("hi", "hello", "bye", "helol", "abc", "cab",
"bac", "silenced", "licensed", "declines")
print(anagram(keywords))
Notez que la construction de Counter
est O(l)
, tandis que chaque mot est trié par O(n*log(l))
où l est la longueur du mot.
Résolution d'anagrammes à l'aide de nombres premiers
Il s'agit d'une solution plus avancée, qui repose sur le "caractère unique multiplicatif" des nombres premiers. Vous pouvez vous référer à cet article SO: Comparaison d'anagrammes à l'aide de nombres premiers , et voici un exemple de mise en oeuvre en python .
Solution simple en Python :
def anagram(s1,s2):
# Remove spaces and lowercase letters
s1 = s1.replace(' ','').lower()
s2 = s2.replace(' ','').lower()
# Return sorted match.
return sorted(s1) == sorted(s2)
J'utilise un dictionnaire pour stocker chaque caractère de chaîne un par un. Ensuite, parcourez la deuxième chaîne et trouvez le caractère dans le dictionnaire. Si c'est le cas, diminuez le nombre de clés correspondantes dans le dictionnaire.
class Anagram:
dict = {}
def __init__(self):
Anagram.dict = {}
def is_anagram(self,s1, s2):
print '***** starting *****'
print '***** convert input strings to lowercase'
s1 = s1.lower()
s2 = s2.lower()
for i in s1:
if i not in Anagram.dict:
Anagram.dict[i] = 1
else:
Anagram.dict[i] += 1
print Anagram.dict
for i in s2:
if i not in Anagram.dict:
return false
else:
Anagram.dict[i] -= 1
print Anagram.dict
for i in Anagram.dict.keys():
if Anagram.dict.get(i) == 0:
del Anagram.dict[i]
if len(Anagram.dict) == 0:
print Anagram.dict
return True
else:
return False
La plupart des réponses précédentes sont correctes, voici un autre moyen de comparer deux chaînes ..__ Le principal avantage de l’utilisation de cette stratégie par rapport à celle du tri est la complexité espace-temps qui est n log of n .
1.Vérifiez la longueur de la chaîne
2. Construire fréquence Dictionnaire et comparer si les deux correspondent, alors nous avons identifié des mots anagramme
def char_frequency(Word):
frequency = {}
for char in Word:
#if character is in frequency then increment the value
if char in frequency:
frequency[char] += 1
#else add character and set it to 1
else:
frequency[char] = 1
return frequency
a_Word ='google'
b_Word ='ooggle'
#check length of the words
if (len(a_Word) != len(b_Word)):
print ("not anagram")
else:
#here we check the frequecy to see if we get the same
if ( char_frequency(a_Word) == char_frequency(b_Word)):
print("found anagram")
else:
print("no anagram")
import collections
def find_anagrams(x):
anagrams = [''.join(sorted(list(i))) for i in x]
anagrams_counts = [item for item, count in collections.Counter(anagrams).items() if count > 1]
return [i for i in x if ''.join(sorted(list(i))) in anagrams_counts]
Cela fonctionne bien:
def find_ana(l):
a=[]
for i in range(len(l)):
for j in range(len(l)):
if (l[i]!=l[j]) and (sorted(l[i])==sorted(l[j])):
a.append(l[i])
a.append(l[j])
return list(set(a))
Celui-ci va vous aider:
En supposant que l'entrée est donnée sous forme de chaînes séparées par des virgules
entrée de la console: abc, bac, voiture, rac, pqr, acb, acr, abc
in_list = list()
in_list = map(str, raw_input("Enter strings seperated by comma").split(','))
list_anagram = list()
for i in range(0, len(in_list) - 1):
if sorted(in_list[i]) not in list_anagram:
for j in range(i + 1, len(in_list)):
isanagram = (sorted(in_list[i]) == sorted(in_list[j]))
if isanagram:
list_anagram.append(sorted(in_list[i]))
print in_list[i], 'isanagram'
break