List comprehensions - when do elements get added to the new list?

I’m trying to use a list comprehension to create a list of the letters that two strings have in common without any duplicates. This function doesn’t work like I expected. The duplicates are still there. Does lst not update as the list comprehension goes through the for loop?

def create_list_of_common_letters(string_one, string_two): 
  lst = []
  lst = [letter 
         for letter in string_one 
         if (letter in string_two) and (not letter in lst)
        ]
  
  return(lst)
1 Like

If list comprehension updated some list, then you wouldn’t need to assign the result of list comprehension to a variable, you would already have a fully populated list.

  lst = []
  [letter 
   for letter in string_one 
   if (letter in string_two) and (not letter in lst)
   ]  # discarded
  return lst  # empty, nobody touched it

We cannot poll the list while we are building it with a comprehension. That comprehension IS the list, and it only gets assigned when it is completely generated. The error would be something like ‘variable accessed before it is defined.’

First thing to note, we do not need to define an empty list when using a comprehension. It is the definition of the list by virtue of the [] in the expression.

What if we start with just a comprehension to find letters in common whether unique or not?

common_letters = [letter for letter in string_one if letter in string_two]

This will contain possible duplicates, but now we have an actual list we can poll. Now we just need to remove the duplicates. I’ll leave that for the member to play with and sort out, for now.

Something that may not have been introduced in this unit is the other type of comprehensions, namely dict comprehension and set comprehension. The one that applies to this situation is the set.

Consider,

common_letters = list(set([letter for letter in string_one if letter in string_two]))

This will result in a list of unique letters. More simply,

>>> a = 'twelve anry men'
>>> b = 'justice delayed is justice denied'
>>> list({letter for letter in a if letter in b})
['n', 'l', 'y', 'a', ' ', 't', 'e']
>>> list({letter for letter in a if letter in b and letter.isalpha()})
['n', 'l', 'y', 'a', 't', 'e']
>>> 
2 Likes

Great clear answer. And because I was unnecessarily defining lst before the comprehension, I didn’t get a “variable accessed before it’s defined” error. So my first mistake made the second mistake harder to see.

Thanks!

You’re welcome! The concept of finding and excluding duplicates can be explored in any number of ways. The first way will be to use a naive algorithm (loops) and then study it for clues on how to construct the same as a comprehension. While comprehensions can be so much more simple on the surface, they do come with some in’s and out’s that will gradually come to light if we play with them for a good while.

Taking sets into account (another concept to explore and learn) we could write a simple comprehension if we do, as advised by @ionatan, treat the two input strings as sets…

>>> [c for c in set(a) if c in set(b) and c.isalpha()]
['n', 'l', 'y', 'a', 't', 'e']
>>> 

This is not a panacea, as simple and succinct as it is. We really do need the practice with loops, and should not throw out the baby with the bath water.

P. S. Please post a link to this exercise so we can play around in that page.

1 Like

I’m not sure if this is the proper way to share the link but hopefully this works: Introduction to Strings - Strings and Conditionals (Part Two)

1 Like

We see that this lesson can be solved using the iterative approach with a conditional and a helper function (a predicate)…

def contains(a, b):
    return b in a    # returns a boolean

def common_letters(m, n):
    common = []
    for x in n:
        if contains(m, x) and not contains(common, x):
            common.append(x)
    return common

Not sure the concept of comprehensions is introduced at this time, but time spent studying this on your own is time well spent.

This topic was automatically closed 18 hours after the last reply. New replies are no longer allowed.