Я хочу найти все слова, которые имеют определенный набор целевых букв. Мой код работает, когда ни одна из букв в цели не повторяется, но не в том случае, если есть повторы.
Вот мой код:
target = 'bba'
target_words = [
'aani', 'aaru', 'abac', 'abas',
'abba', 'abby', 'abed', 'abel', 'abet'
]
target_list = list(target)
final_list = []
for word in target_words:
word_list = list(word)
if (all(x in word_list for x in target_list)):
final_list.append(word)
print('Final list: ', final_list)
Выход Final list: ['abac', 'abas', 'abba', 'abby', 'abed', 'abel', 'abet']
Я бы хотел, чтобы это было Final list: ['abba', 'abby']
Я не могу найти способ получить желаемый результат. Это может быть потому, что я преобразовываю буквы слов в список, но я не вижу, как это сделать иначе.
Кстати, зачем ты это делаешь target_list = list(target)
? Почему бы просто не использовать target
? Точно так же word_list = list(word)
... вы могли бы просто all(x in word for x in target_list)
не создавать бессмысленных промежуточных списков.
@JLPeyret Он действительно должен правильно обрабатывать abbb
; то есть лишние b
разрешены.
@juanpa.arrivillaga Честный ответ заключается в том, что я все еще новичок в Python и еще не полностью понял многие тонкости. На мой взгляд, если я хочу увидеть, присутствует ли набор букв в любом порядке в наборе других букв, мне нужно рассматривать каждую букву как вещь.
@jcherfas строка — это последовательность отдельных букв. Посмотрите, что произойдет, если вы сделаете data = "abc"
, а затем print(data[0])
или for c in data: print(c)
Конечно, вы правы, и я знаю это, потому что использую len(data)
, но я еще не полностью усвоил это. data.split()
также дает мне понять это.
Это хороший вариант использования collections.Counter()
. Это дает нам простой способ проверить, существует ли желаемое совпадение между словом в target_words
и target
, учитывая повторяющиеся буквы:
from collections import Counter
[word for word in target_words if Counter(word) & Counter(target) == Counter(target)]
Если вы хотите оптимизировать это, вы можете создать Counter
для target
заранее, чтобы не восстанавливать его для каждого слова, как утверждает азро:
from collections import Counter
target_counter = Counter(target)
[word for word in target_words
if Counter(word) & target_counter == target_counter]
Оба этих вывода:
['abba', 'abby']
Counter(target)
можно строить раз и навсегда, а не 2 раза на слово списка
Отредактировано в исходный ответ (с указанием авторства). Спасибо за предложение!
В Python 3.10+ вы можете просто сделать Counter(word) >= target_counter
вместо Counter(word) & target_counter == target_counter
@BrokenBenchmark Большое спасибо за ваше решение и за то, что познакомили меня с collections.Counter()
. Я вижу, что могу найти применение этому подходу в других вещах, которые я пытаюсь сделать.
Сначала давайте найдем уникальные буквы в вашем целевом слове.
target_word_letters = set(target)
Теперь мы можем использовать понимание словаря, чтобы получить количество каждой буквы.
counts = {letter: target.count(letter) for letter in target_word_letters}
Теперь нам нужно понимание списка, которое перебирает target_words
и проверяет, что для каждой буквы в counts
такое же количество (или больше) этой буквы находится в целевом слове.
[word for word in target_words if all(word.count(l) >= c for l, c in counts.items())]
Результат:
['abba', 'abby']
Как это должно обрабатываться
abbb
? У этого есть ваши цели, но должны ли дополнительныеb
дисквалифицировать его? Это имеет отношение к ответу @BrokenBenchmark