web-dev-qa-db-ja.com

Pythonを使用して、単語のリストのアナグラムを見つける

たとえば、文字列のリストがある場合:

["car", "tree", "boy", "girl", "arc"...]

そのリストでアナグラムを見つけるにはどうすればよいですか?例えば ​​(car, arc)。各文字列にforループを使用してみました。異なる長さの文字列を無視するためにifを使用しましたが、正しい結果を得ることができませんでした。

文字列内の各文字を調べて、リスト内の他の文字と異なる順序で比較するにはどうすればよいですか?

私はいくつかの同様の質問を読みましたが、答えはあまりにも高度でした。何もインポートできず、基本的な機能しか使用できません。

17
user1040563

2つの文字列に対してこれを行うには、次のようにします。

def isAnagram(str1, str2):
    str1_list = list(str1)
    str1_list.sort()
    str2_list = list(str2)
    str2_list.sort()

    return (str1_list == str2_list)

リストの繰り返しに関しては、かなり簡単です

26
Ofir Farchy

(ソートされたWord、Wordのリスト)の辞書を作成します。同じリストにあるすべての単語は、相互のアナグラムです。

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)

または:

Word_source = ["car", "tree", "boy", "girl", "arc"]
print_anagrams(Word_source)
16
hughdbrown

解決策の1つは、アナグラムを検索しているWordを並べ替えて(たとえばsortedを使用して)、代替を並べ替えて比較します。

したがって、リストで「rac」のアナグラムを検索する場合は、['car', 'girl', 'tofu', 'rca']、コードは次のようになります。

Word = sorted('rac')
alternatives = ['car', 'girl', 'tofu', 'rca']

for alt in alternatives:
    if Word == sorted(alt):
        print alt
7
Felix Loether

各要素を並べ替えてから、重複を探します。ソート用の組み込み関数があるので、何もインポートする必要はありません

4
Christian Alis

この問題には複数の解決策があります。

  1. 古典的なアプローチ

    最初に、アナグラムを定義するものを考えてみましょう:2つの単語が同じ文字のセットで構成され、各文字がまったく同じ数である場合、互いにアナグラムです両方の単語の時間。これは基本的に、各単語の文字数のヒストグラムです。これは_collections.Counter_データ構造の完璧な使用例です( docsを参照 )。アルゴリズムは次のとおりです。

    • キーをヒストグラムにし、値をこのヒストグラムを持つ単語のリストにする辞書を作成します。
    • Wordビルドごとにヒストグラムを作成し、このヒストグラムに対応するリストに追加します。
    • 辞書値のリストを出力します。

    コードは次のとおりです。

    _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))
    _

    Counterの構築はO(l)であり、各WordのソートはO(n*log(l))であることに注意してください(lはWordの長さです)。

  2. 素数を使用してアナグラムを解く

    これは、より高度なソリューションであり、素数の「乗算的一意性」に依存しています。これを参照することができますSO post: 素数を使用したアナグラムの比較 、および サンプルpython実装です

2

何もインポートできないため、要求したforループを含む2つの異なるアプローチがあります。

アプローチ1:Forループと組み込みソート関数

Word_list = ["percussion", "supersonic", "car", "tree", "boy", "girl", "arc"]

# initialize a list
anagram_list = []
for Word_1 in Word_list: 
    for Word_2 in Word_list: 
        if Word_1 != Word_2 and (sorted(Word_1)==sorted(Word_2)):
            anagram_list.append(Word_1)
print(anagram_list)

アプローチ2:辞書

def freq(Word):
    freq_dict = {}
    for char in Word:
        freq_dict[char] = freq_dict.get(char, 0) + 1
    return freq_dict

# initialize a list
anagram_list = []
for Word_1 in Word_list: 
    for Word_2 in Word_list: 
        if Word_1 != Word_2 and (freq(Word_1) == freq(Word_2)):
            anagram_list.append(Word_1)
print(anagram_list)

これらのアプローチをより詳細に説明したい場合は、 記事 をご覧ください。

以前の回答のほとんどは正しいです。2つの文字列を比較する別の方法があります。この戦略をソートと比較して使用する主な利点は、空間/時間の複雑さであり、これは n log of n です。

1.文字列の長さを確認する

2.頻度辞書を作成し、両者が一致するかどうかを比較して、アナグラムの単語を特定しました

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")
1
grepit
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"])
1
kinjal patel

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)
0
Zaid Bhat

辞書を使用して、文字列の各文字を1つずつ保存しています。次に、2番目の文字列を反復処理し、辞書内の文字を見つけます。文字が存在する場合は、辞書の対応するキーの数を減らします。

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
0
Mr. Wonderful
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]
0
A.Kot

これはうまくいきます:


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))

0
Bhavya Geethika

これはあなたを助けるつもりです:

入力がコンマ区切りの文字列として与えられていると仮定

コンソール入力:abc、bac、car、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
0
frp farhan

pythonのソリューションは以下のようになります:

class Word:
    def __init__(self, data, index):
        self.data = data
        self.index = index

def printAnagrams(arr):
    dupArray = []
    size = len(arr)

    for i in range(size):
        dupArray.append(Word(arr[i], i))

    for i in range(size):
        dupArray[i].data = ''.join(sorted(dupArray[i].data))

    dupArray = sorted(dupArray, key=lambda x: x.data)

    for i in range(size):
        print arr[dupArray[i].index]

def main():
    arr = ["dog", "act", "cat", "god", "tac"]

    printAnagrams(arr)

if __name__== '__main__':
    main()
  1. 最初に、位置インデックスを表すインデックスを持つ同じ単語の重複リストを作成します。
  2. 次に、重複リストの個々の文字列をソートします
  3. 次に、文字列に基づいて重複リスト自体をソートします。
  4. 最後に、重複した配列から使用されたインデックスで元のリストを印刷します。

上記の時間の複雑さは、O(NMLogN + NMLogM)= O(NMlogN)です。

0
Rookie