Jordan Hunt
Jordan Hunt

Reputation: 11

Python for loop help, appending to lists

>> find_sub_anagram_in_wordlist('apple', ['ppl','al','app','apple'])

['ppl']

Why does the loop not add the other sub-anagrams?

Here is my code:

anagramList = []

def find_sub_anagram_in_wordlist(str, str_list):

    global anagramList
    anagramList.clear()
    list1 = list(str)
    list1.sort()
    for word in str_list:
        shouldAdd = True
        listi = list(word)
        listi.sort()
        for j in listi:
            if j in list1:
                list1.remove(j)
            else:
                shouldAdd = False
        if shouldAdd == True:
            anagramList.append(word)
    return anagramList

Upvotes: 1

Views: 65

Answers (2)

R Nar
R Nar

Reputation: 5515

This line:

if j in list1:
    list1.remove(j)

is your problem. Think about the first iteration of for word in str_list where word == 'ppl

going through the following code with that in mind:

    for j in listi: #for every char in word, 'p', 'p', 'l'
        if j in list1: 'True for all three
            list1.remove(j) 'removes all three letters
        else:
            shouldAdd = False

this leaves you with list1 == ['a','e']. Your next iteration for word gives you word == 'al'. If we go through the above code again, you'll see that since there is no longer 'l' in list1, shouldAdd == False. Also, since a was in it, it now isn't and list1 == ['e']. You can see where this is going.

Using your code, you can fix this by moving list1 = list(str) to inside of your for word in str_list: loop so that it reinitializes the list every time. I am going to try to find a more pythonic way of doing the function and post it when I can.

EDIT:

Here is my way of doing this:

>>> def is_sub_anagram(s, sub):
    s = list(s)
    try:
        for c in sub: s.remove(c)
    except:
         return False
    return True
>>> def find_sub_anagram_in_wordlist(s, str_list):
    return list(filter(lambda x: is_sub_anagram(s,x), str_list))

>>> find_sub_anagram_in_wordlist('apple',['app','ppl','ae','le'])
['app', 'ppl', 'ae', 'le']

>>> find_sub_anagram_in_wordlist('apple',['app','ppl','ae','le','lle'])
['app', 'ppl', 'ae', 'le']

Upvotes: 1

jez
jez

Reputation: 15369

I think it will help to simplify what you're doing. In particular, separate the test for subanagramness functionally from the procedure for filtering the candidates. This would be my approach:

def is_sub_anagram( word, candidate ):
    word = list( word )
    for letter in candidate:
        try:
            word.remove( letter )
        except ValueError:
            return False
    return True


def filter_sub_anagrams( word, candidates ):
    return [ x for x in candidates if is_sub_anagram( word, x ) ]


print( filter_sub_anagrams( 'apple', [ 'ppl', 'al', 'app', 'apple', 'aapl' ] ) )

The output is:

['ppl', 'al', 'app', 'apple']

Note that 'aapl' is not and should not be included in the output.

Upvotes: 1

Related Questions