Used a brute force method; is it a bit messy?

The interpreter is order sensitive, so [a, b] != [b, a], if anyone has a better/clever solution please share. Used a brute force method so its a bit messy:


def contains(big_string, little_string):
  return little_string in big_string

def common_letters(string_one, string_two):
  
  pairs = []
  str1 = len(string_one)
  min = str1
  str2 = len(string_two)
  max = str2
  
  if str1 > str2:
    max = str1
    min = str2
    for letter in range(0, min, 1):
      if contains(string_one, string_two[letter]):
        pairs.append(string_two[letter])
  else:
    for letter in range(0, min, 1):
      if contains(string_two, string_one[letter]):
        pairs.append(string_one[letter])
  
  for i in range(0, len(pairs), 1):
    for j in range(i + 1, len(pairs), 1):
      if pairs[j] == pairs[i]:
        return pairs[:j]
  return list(set(pairs))
   
print(contains("banana", "cream"))
print(common_letters('manhattan', 'san francisco'))
print(common_letters('python', 'ruby on rails'))
1 Like

What is the output of the three print statements?

This may not be clever, and if sets have not come up yet it will be out of place. However, since your return value is a set, we may as well explore it…

>>> a = set('abdigmqry')
>>> b = set('bimfhoy')
>>> a
{'q', 'i', 'a', 'b', 'd', 'm', 'g', 'y', 'r'}
>>> b
{'i', 'b', 'm', 'o', 'h', 'y', 'f'}
>>> a.intersection(b)
{'m', 'i', 'b', 'y'}
>>> 
>>> a, b = 'manhattan', 'san francisco'
>>> set(a).intersection(set(b))
{'n', 'a'}
>>> a, b = 'python', 'ruby on rails'
>>> set(a).intersection(set(b))
{'n', 'y', 'o'}
>>> 

The only real problem with all this simplicity is we lose the orginal order, though that is hardly a real problem. But, if we wish to preserve the order, then sets are out (as are dictionaries).

We discussed earlier how we only need to iterate over one string, a character at a time, and compare it to the other string. If it has not yet been cached in the return list, then append it. Once the string has been completely iterated, return the resulting list.

spoiler
  common = []
  for x in string_one:
    if x in string_two:
      if x not in common:
        common.append(x)
  return common

Since the lesson is specifically focusing on the in operator, we should make use of it in our solution so we have an example to come back to in future.

2 Likes

If you care about letter counts, collections.Counter also supports intersection


found a bug by reading it

common_letters('aab', 'aab')

Because this looked incredibly shady:

There’s no reason why you would have seen all all in-common letters at that point, so a counter example is easily constructed with a letter re-appearing before all others have been seen.

I got suspicious seeing that the code had a special case to a problem that doesn’t really have special cases. Find and de-duplicate, right? That doesn’t fork off into two paths, just do one and then the other.

2 Likes

def common_letters1(string_one, string_two):
common_list =
for character_one in string_one:
for character_two in string_two:
if character_one == character_two:
common_list.append(character_one)
common_letter = set(common_list)
return common_letter

This is my suggestion for how to solve the task. Since sets are not yet introduced in the scope of this exercise I used the in keyword again to check if the matched character was already in my list of common_letters before appending it.

def common_letters(string_one, string_two):
  common_letters = []
  for letter in string_one:
    if letter in string_two:
      if letter not in common_letters:
        common_letters.append(letter)
  return common_letters
5 Likes
def common_letters(string_one, string_two):
  common = []
  for i in range(len(string_one)):
    if string_one[i] in string_two and not string_one[i] in common:
      common.append(string_one[i])
    else:
      continue
  return common

Is there a question to go with this? Please don’t post to post.

def common_letters(string_one,string_two):
  foo = []
  for letter in string_one:
    if letter in string_two and letter not in foo: foo += letter
  return foo

I’m sure there are even more compact ways to do this if you know more of the methods available in python

1 Like

It’s a direct answer to the question in the original post

if anyone has a better/clever solution please share.

Nothing of the sort. It only comes so long after the OP as to have a need for some sort of explanation accompanying it. Just dropping in a piece code on a moribund thread is something of a distubance. Who is being answered?

Don’t know if this helps, but this was my method.

def common_letters(string_one, string_two):
same_letters =
for letter in string_one:
if letter in string_two and same_letters.count(letter) == 0:
same_letters.append(letter)
return same_letters

def common_letters(string_one, string_two):
  a = []
  for i in string_one:
    if i in string_two and i not in a:
    	a.append(i)
  return(a)
1 Like

I am not good enough to understand your code. But this worked for me:

def common_letters(string_one, string_two): 
  shared_letters = []
  for letter in string_one:
    if letter in string_two and letter not in shared_letters:
      shared_letters.append(letter)
  return shared_letters

print(common_letters('banana', 'cream'))

@petercook0108566555, which code are you “not good enough to understand”? The example immediately above yours is identical, except for the variable names.

Sorry I was referring to this code:

def contains(big_string, little_string):
  return little_string in big_string

def common_letters(string_one, string_two):
  
  pairs = []
  str1 = len(string_one)
  min = str1
  str2 = len(string_two)
  max = str2
  
  if str1 > str2:
    max = str1
    min = str2
    for letter in range(0, min, 1):
      if contains(string_one, string_two[letter]):
        pairs.append(string_two[letter])
  else:
    for letter in range(0, min, 1):
      if contains(string_two, string_one[letter]):
        pairs.append(string_one[letter])
  
  for i in range(0, len(pairs), 1):
    for j in range(i + 1, len(pairs), 1):
      if pairs[j] == pairs[i]:
        return pairs[:j]
  return list(set(pairs))
   
print(contains("banana", "cream"))
print(common_letters('manhattan', 'san francisco'))
print(common_letters('python', 'ruby on rails'))

Ask yourself, “What is the code attempting to do?” Then go back in your mind and think how would you do it?

Don’t look at the code. It will infect your mind. Come up with a strategy, then, and only then, look at the code. If you agree with it, then it must have some meaning. If you don’t, then clearly it does not. Set it aside. Don’t give time to unproven code, or code that seems to take forever to do something. It warps your sense of logic. If in the end, the code is what you eventually came up with through your trials. then it has veracity beyond question. When you and me arrive at the same conclusion, we’re both right.

I used the “continue” thing:

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

I used this code and it worked. I used a nested for loop.

def common_letters(string_one, string_two):
    matching =[]
    for character in string_one:
        for character in string_two:
            if character in string_one and character in string_two and character not in matching:
                matching.append(character)
    return matching

The code following code also works assuming you still have the contains function:



def common_letters(string_one, string_two):
    matching =[]
    for character in string_one:
        for character in string_two:
            if contains(string_one, character) == True and contains(string_two, character) == True and character not in matching:
                matching.append(character)
    return matching```

Post solution code here and expect one of three things:

  1. Solution deleted, as it does not actually benefit learners as we would hope.
  2. Solution is ignored, as it does not meet with learner’s comprehension of the problem, or is just plain wrong.
  3. Solution is criticized (meaning analyzed and critiqued) and the take away for learners is the insights gained from said criticism.

In this case I go with door number three.

Learners need to grasp early on how to identify booleans. Reason being, it promotes quick movement up the logic chain when it comes to writing expressions that yield one or other of the two.

We already know that if and while both operate on booleans, the only thing they can operate upon. That makes them both predicate operators, of a sort. A branch in the flow is chosen by one of two options.

Okay, now to my first criticism: Comparing to a boolean.

This is redundant.

if a == True:

is the penultimate of,

if a:

but also quite moot, as it stands.

If a can have only one of two states, it is binary, and is castable to one or the other of the two bool objects.

Second, although not stressed, is the order in which we measure containment.

if not contains(matching, character):
    char = contains(string_one, character) \
    and contains(string_two, character)
    if char:
        matching.append(character)
def contains(structure, value):
  return value in structure

matching = []
str_one = 'supercalifragilisticexpialdocious'
str_two = 'theraininSpainfallsmainlyontheplains'
for character in str_one if len(str_one) > len(str_two) else str_two:
  if not contains(matching, character):
    char = contains(str_one, character) \
    and contains(str_two, character)
    if char:
        matching.append(character)
print (matching)
['t', 'e', 'r', 'a', 'i', 'p', 'f', 'l', 's', 'o']

print (sorted(filter(lambda x: x not in str_two, str_one)))
print (sorted(filter(lambda x: x not in str_one, str_two)))
['c', 'c', 'c', 'd', 'g', 'u', 'u', 'x']
['S', 'h', 'h', 'm', 'n', 'n', 'n', 'n', 'n', 'n', 'y']