Как отфильтровать слова хотя бы с одной уникальной буквой

#python

#python

Вопрос:

У меня есть длинный список вызываемых строк words . Все строки имеют одинаковую длину, равную 5. Для любого i в {0, …,4} мы можем проверить, является ли i ‘-я буква строки также i-й буквой любой другой строки в списке. Мы называем букву в i ‘-й позиции уникальной, если это не так.

Я хотел бы удалить все строки из моего списка, для которых существует любая i , для которой i ‘-я буква уникальна.

В качестве очень простого примера рассмотрим: words = ["apple", "amber", "bpple", "bmber", "appld"] . Строка «appld» должна быть удалена, поскольку d уникальна в 4-й позиции.

Есть ли аккуратный способ сделать это?

Комментарии:

1. Составьте список, элементы которого соответствуют каждому из исходных слов. Каждый элемент списка — это количество дубликатов соответствующей буквы. Когда вы закончите, удалите каждый элемент исходного списка, соответствующий списку, который содержит 1 .

Ответ №1:

Использование collections.Counter и zip(*...) идиома транспозиции:

 from collections import Counter

# counts for every index
bypos = [*map(Counter, zip(*words))] 

# disallow count 1 for any letter x in its respective position
words = [w for w in words if all(c[x]!=1 for x, c in zip(w, bypos))]
# ['apple', 'amber', 'bpple', 'bmber']
 

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

Некоторые документы по используемым здесь утилитам:

Ответ №2:

это можно сделать в O (NlogN), но пространство неэффективно

 d={}
for j,w in enumerate(words):
    for i,c in enumerate(w):
        if (i,c) in d:
            d[(i,c)].append(j)
        else:
            d[(i,c)]=[j]
for i in reversed(list(set([v[0] for v in d.values() if len(v)==1]))):
    words.pop(i)
print(words)