How to not get duplicate letters?

Couple of observations.

  • In a previous exercise you returned a bool with a single line. Why not here in contains()?

  • In common_letters what difference does it make which list is longer?

We really only need to iterate the shorter list and check for membership in the longer one.

1 Like

Have not yet encountered dictionary comprehension. That’s awesome! Figured out a list comprehension solution:

>>> def common_letters(short, long):
      if len(short) > len(long): short, long = long, short
      return [l for i, l in enumerate(short) if l in long and l not in short[:i]]

>>> common_letters('impossible', 'impasse')
['i', 'm', 'p', 's', 'e']
>>>

1 Like

That is the natural progression from algo to expression.

I chose the dict comprehension to eliminate the conditional. Dictionaries cannot have duplicate keys (they simply get created or updated) so we end up with a unique list in the end.

1 Like

Not to do any policing… more to make a few notes…

A tiny bit of refactoring (exactly the same thing but shaking it until the loose parts fall off)

def contains(a, b):
  return b in a

…right? Where’s the loop! Conceptually there’s need to step through the small one, and compare each letter to each letter in the big one, and see if it’s possible to go the whole way (a match)

And then this:

new = []
...
i not in new

Use a set, not a list. Sets support insertion and lookup without searching through the values.
In terms of notreallydoingityourself, sets also have exactly this whole thing as a supported operation: intersection
edit: well, actually, for a small sized list this is 100% fine, but if we were to generalize the problem such that we don’t know how many values there may be in it, then definitely set

Oh and it’s twice as long as it needs to be isn’t it? You only need one of those, they look the same and you only run one of them, so there should be only one of them.

An interesting variation is to also include the amount of each letter they have in common. As far as sets go this is called a multiset, it’s more of a dictionary with a count, but with set operations. In python this is called Counter. Counting how many there are of each letter by searching through each word once for each character would be inefficient, it can be done better than that.

1 Like

Apart from a dictionary comprehensions, set comprehensions can also be used to implement common_letters:

def common_letters(one, two):
  return list({c for c in one if c in two})
1 Like

Using list you can avoid duplicate characters this way
common_characters

I will appeal to every learner here to please take their time to read this link set comprehension as posted by @patrickd314. Thank you so much Patrick

1 Like

Using the AND NOT structure I was able to get the code running, but it does not work if I use capital letters! If I try to run :

common_letters(“Paris”, “pain”)

it will return:

[‘a’, ‘i’]

Somehow the P character was ignored. Why is that?

“P” and “p” are like ‘apple’ and ‘orange’ by comparison. They are completely different characters from which Python draws no connection. Somewhere in the logic, change inputs to lowercase before testing and both should pass.

if a.lower() == b.lower():
1 Like

I see. Thank you very much, i didn’t know that.

1 Like

I was really happy with how I got this one. I don’t know how efficient or proper the code is, but it worked well enough.

def common_letters(string_one, string_two):

  common = []

  for a in string_one:

    if a in string_two:

      if a in common:

        continue

      common += a

   return common

Yes, there are multiple ways of solving this problem as another poster did using dictionaries. However, my assumption would be neither sets nor dictionaries have been covered up to this point in the course. Even if they had been, the directions specifically call for using loops and lists so it is this knowledge that is being tested.

1 Like

Several people in this post have mentioned not knowing about the “not” operator. I’m curious about this. I’m not taking this course so I don’t know what the order of topics being covered is but certainly “if” statements must have been. Generally when learning about “if” statements the comparison operators ie. (>, <, >=, etc ) as well as the logical operators (“and”, “or”, and “not”) are also introduced. Is this not the case?

1 Like

Just to emphasize, the parentheses around “letter in common” are VERY important. If it isn’t written as
such but rather “not letter in common” the expression will evaluate to “not letter (in common)”. These two expressions are completely different and won’t give the same result.

That is how I also solved it, but compressed it a little bit more with “and not”:

def common_letters(string_one, string_two):
  output = []
  for i in range(len(string_one)):
    if string_one[i] in string_two and not string_one[i] in output:
      output.append(string_one[i])
  return output

I the letter in position string_one[i] returns TRUE as per first condition AND is not already present in output, then it appends said letter to the list output :slight_smile:

Should that be,

output.append(...)
^^^^^^

apologies, I edited the code I pasted but forgot that bit…

1 Like

Same happened to me, with this line I fixed it:

if letters in common_letters:
        continue

whole code is below:

def common_letters(string_one, string_two):
  common_letters = []
  for letters in string_one:
    if letters in string_two:
      if letters in common_letters:
        continue
      common_letters.append(letters)
  return common_letters

You can combine conditions with and/or

1 Like