jcherfas
jcherfas

Reputation: 25

List comprehension when there are repeated elements in both lists

I want to find all words that have a particular set of target letters. My code works when none of the letters in the target is repeated, but not if there are repeats.

Here is my code:

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)

The output is Final list: ['abac', 'abas', 'abba', 'abby', 'abed', 'abel', 'abet']

I would like it to be Final list: ['abba', 'abby']

I cannot find a way to get the result I want. It may be because I am converting the letters of the words into a list, but I don't see how to do it otherwise.

Upvotes: 1

Views: 91

Answers (2)

BrokenBenchmark
BrokenBenchmark

Reputation: 19243

This is a good use case for collections.Counter(). It gives us a clean way to check whether the desired overlap exists between a word in target_words and the target, accounting for duplicate letters (with a suggested improvement by azro):

from collections import Counter

target_counter = Counter(target)
[word for word in target_words if Counter(word) & target_counter == target_counter]

This outputs:

['abba', 'abby']

Upvotes: 3

Chris
Chris

Reputation: 36496

First let's find the unique letters in your target word.

target_word_letters = set(target)

Now, we can use a dictionary comprehension to get a count of each letter.

counts = {letter: target.count(letter) for letter in target_word_letters}

Now we need a list comprehension that iterates over target_words and checks that for every letter in counts, the same number (or more) of that letter is in the target word.

[word for word in target_words if all(word.count(l) >= c for l, c in counts.items())]

Result:

['abba', 'abby']

Upvotes: 0

Related Questions