2015-06-20 2 views
2

Я пытаюсь пройти через массив и удалить элементы, которые не являются анаграммами в python. Вот код, который я написал. Моя логика кажется прекрасной, но я не могу ее получить.Фильтр Anagram в массиве в Python

b = ['cat', 'dog', 'god', 'star', 'lap', 'act'] 
array=[] 
t=0 
for i in b: 
    while t<len(b): 
     if ''.join(sorted(i))==''.join(sorted(b[t])): 
      array.append(i) 
     t+=1 
print array 
+0

Вы имеете в виду, что все элементы массива должны быть анаграммами в вашем результате? – shunya

ответ

1

Только некоторые незначительные изменения в вашем существующем коде должны работать.

b = ['cat', 'dog', 'god', 'star', 'lap', 'act'] 
array = [] 
t = 0 
for i, value in enumerate(b): 
    t = i+1 
    while t<len(b): 
     if ''.join(sorted(value))==''.join(sorted(b[t])): 
      array.extend([value, b[t]]) 
     t+=1 
print array 
['cat', 'act', 'dog', 'god'] 
+0

OMG! СПАСИБО! и это имеет большой смысл; –

+0

Добро пожаловать. Также, пожалуйста, примите ответ, если он решит вашу проблему. – Akshay

+0

Спасибо! Я новичок на этом сайте. –

0

Первый выпуск в вашей программе, является то, что вы инициализацией t к 0 вне для цикла, следовательно, вы вы только проверить первый элемент b со всеми элементами, для остальных итераций for loop, t всегда будет больше len (b), поэтому он никогда не выходит во внутренний цикл, от второй итерации цикла for. Простое исправление -

for i in b: 
    t = 0 
    while t<len(b): 
     if ''.join(sorted(i))==''.join(sorted(b[t])): 
      array.append(i) 
     t+=1 

Но для поиска анаграмм, я думаю, что вы чрезмерно усложнять его, вы можете просто найти сумму значений ASCII этих символов строки, а затем сравнить его с другими одинаковые суммы и длины, и проверьте, соответствуют ли обе суммы значения ASCII и длина строки, если они являются анаграммой.

Пример кода для этого метода -

b = ['cat', 'dog', 'god', 'star', 'lap', 'act'] 
c = list(map(len,b)) 
d = list(map(lambda x: sum([ord(c) for c in x]), b)) 
arr= [] 
for i, s in enumerate(b): 
    for j, s1 in enumerate(b): 
      if d[i] == d[j] and c[i] == c[j] and i != j: 
        if s not in arr: 
          arr.append(s) 
        if s1 not in arr: 
          arr.append(s1) 
print(arr) 
>> ['cat', 'act', 'dog', 'god'] 
+0

Спасибо за объяснение и урок! –

+0

Добро пожаловать. Кроме того, не забудьте принять любой ответ, который решил вашу проблему. Помогло бы сообществу много –

0

Альтернативный подход

Использование itertools GroupBy

In [18]: from itertools import groupby 


In [19]: c=[list(g) for k,g in groupby(sorted(b,key=sorted),sorted)] 

In [20]: c 
Out[20]: [['cat', 'act'], ['lap'], ['star'], ['dog', 'god']] 

In [21]: [x for _list in c if len(_list)>1 for x in _list] 
Out[21]: ['cat', 'act', 'dog', 'god'] 

Ключевым моментом здесь является использование itertools.groupby из itertools модуль, который будет группировать элементы в списке вместе.

Список, который мы поставляем groupby, должен быть отсортирован в расширенном виде, поэтому мы передаем , он отсортирован (b, key = отсортирован). Трюк здесь в том, что отсортированный может взять ключевую функцию и будет сортироваться на основе результатов этой функции, поэтому мы передаем отсортированную снова как ключевую функцию, и это будет сортировать слова , используя буквы строки в порядке. Нет необходимости в определить нашу собственную функцию или создать лямбду.

groupby выполняет ключевую функцию, которую он использует, чтобы указать, должны ли элементы быть сгруппированы вместе и снова, мы можем просто передать ему встроенную функцию сортировки .

Источник: Finding and grouping anagrams by Python

+0

Я бы хотел избежать использования библиотеки для практических целей; Несмотря ни на что, мне все равно придется это узнать, и я ценю ваше объяснение и помощь! Спасибо –

0

На самом деле ваше решение является неправильным, и идея использования 2 for цикла не является эффективным. вы повторяете свой список 2 раза и применяете ''.join(sorted()) 2 раза на своих элементах, и вы сравниваете каждый элемент с самим собой! вместо этого вы можете использовать словарь, чтобы получить индексы элементов анаграммы перебора над enumerate вашим список:

>>> d={} 
>>> for i,j in enumerate(b): 
... d.setdefault(''.join(sorted(j)),[]).append(i) 
... 
>>> d 
{'arst': [3], 'dgo': [1, 2], 'alp': [4], 'act': [0, 5]} 

>>> [b[t] for k in d.values() if len(k)>1 for t in k] 
['dog', 'god', 'cat', 'act'] 

И если вы заботитесь о порядке вы можете использовать OrderedDict функции от collections модуля:

>>> from collections import OrderedDict 
>>> d=OrderedDict() 
>>> for i,j in enumerate(b): 
... d.setdefault(''.join(sorted(j)),[]).append(i) 
... 
>>> [b[t] for k in d.values() if len(k)>1 for t in k] 
['cat', 'act', 'dog', 'god'] 
+1

Спасибо! Хотя это не то, что я искал, я многое узнал из вашего ответа. –

Смежные вопросы