FAQ: Code Challenge: String Methods - Count Multi X

can anyone tell me why this doesn’t work?

def count_multi_char_x(word,x):
count= 0
chunk = word.split(x)
if chunk == x:
count += 1
return count

Why would it work? What exact actions do you mean that should take? If you print out each thing it does, is that what ends up happening? If not, then you’ve answered your own question by showing yourself where it differed from what you expected. Or, if you haven’t thought it through in full, then it definitely shouldn’t work because nobody decided what should happen.

…very helpful, thanks.

def count_multi_char_x(word, x):
  count = 0
  i = word.find(x)
  while (i>=0) and (word != ""):
    word = word[i+1:]
    i = word.find(x)
  return count

Hi ! What do you think about this answer fellow community members ?

We can refactor your solution to simplify…

def count_multi_char_x(word, x):
    count = 0
    while word:
        i = word.find(x)
        if i < 0: break
        count += 1
        word = word[i+1:]
    return count

There is something not very naive about the solution since it uses a built-in with slicing, rather than plain iteration and testing of each position for a match. As learners we should have the basic approach under our belt before moving on to more sophisticated solution approaches.

1 Like

str.find stops when it finds a match meaning that it will in total visit each location only once (except for the first time you use it, that’s a bit inconsistent: you forgot to make the string smaller there)

There’s another problem though, the copies you make of the string does end up being more work than there should be. Rather than copying the string, you could tell str.find where it should start searching.

splits = word.split(x)
return splits
print(count_multi_char_x(“mississipi”, “iss”))

[‘m’, ‘’, ‘ipi’]
can someone explain why theres “” i dont understand why it would do that?

Also why does:
give us [‘m’, ‘ss’, ‘ss’, ‘p’, ‘’]
" in the end. I guess my logic is not clear on this.

str.split() will default to space characters as the separator string, and will preserve only the words in a list. When we supply a separator string (can be one or more characters), the method only preserves what is on either side of that separator. In the above we see that there are no i's preserved in the list, only what was on either side of them.

Occasionally, as in your first example, there may be two such separator strings next to each other, ississ and when we remove the second one it preserves an empty string on its left side, hence, the '', in the list. When the separator is at the end of the string, again it preseves an empty string on its left. This is not a flaw, but the nature of the method.

how about this solution?

def count_multi_char_x(word, x):
splited = word.split(x)
joined = “”.join(splited)
return (len(word) - len(joined))/len(x)

I see many people use split etc. but I thought of this solution:

def count_multi_char_x(word, x):
  return word.count(x)

would that be ok as well?

It depends… Does the exercise suggest an algorithm of our own creation, or does it ask us to use the builtt-in method? Not much to be learned using the the built-in since it does all the heavy lifting and we do nothing.

Can you devise an algo that performs the same task but which exposes its logic to the reader? That would be better practice, one expects.

Wow, I did not realize I needed to use split for this solution.

I’ll try at this again, but my solution without the .split() command was the one from below:

# Write your count_multi_char_x function here:  
def count_multi_char_x(word , x):
  counter = 0
  start = 0
  while len(x) + start < len(word):
    if word[(0 + start) : (len(x) + start)] == x :
      counter += 1
      start += 1
      start += 1

  return counter

# Uncomment these function calls to test your function:
print(count_multi_char_x("mississippi", "iss"))
# should print 2
print(count_multi_char_x("apple", "pp"))
# should print 1      

It was just one approach, and given a string is subscriptable and we are not attempting to mutate it, we don’t need a list, anyway. The string is the list.

The solution you have does not pull any methods out of thin air. That’s what an algorithm looks like.

Plus, Plus.

>>> def count_multi_char_x(word , x):
  counter = 0
  start = 0
  a, b = len(x), len(word)
  while a + start < b:
    if word[(0 + start) : (a + start)] == x :
      counter += 1
    start += 1
  return counter

>>> count_multi_char_x("mississippi", "iss")

I think I’m mssing something :frowning: , to my understanding when you split a string on a character that it also ends with, you’ll end up with an empty string at the end of the list.
the examples show diferent cases :

  • “mississippi”, “iss” we get [‘m’, ’ ’ , ’ ', 'ippi]
  • “apple”, “pp” we get [‘a’,‘le’]
    i dont understand the patern here, if this is the case why I dont get in with the ‘apple’ example [‘a’, ’ ', ‘le’]

Recall that for every character in a string, there are empty strings before and after all characters.

>>> 'aaaaaaa'.split('a')
['', '', '', '', '', '', '', '']

Note that when we split on a, which is seven characters long, the result is eight empty strings.

There must be some reason that we get only one empty string when splitting on p in apple

>>> 'apple'.split('p')
['a', '', 'le']

and no empty strings when splitting on pp

>>> 'apple'.split('pp')
['a', 'le']

How the algorithm sorts this out is a little beyond me though I suspect that it has something to do with the inverse method, join. Any split string should be restorable using str.join() with the same separator string used in the str.split()

>>> 'a'.join(['', '', '', '', '', '', '', ''])
>>> 'p'.join(['a', '', 'le'])
>>> 'pp'.join(['a', 'le'])

As to that algorithm, it will take some research to find and explore the workings behind split and join but that would be chasing down a rabbit hole, at this point in time. Keep this question in mind for extra study once you are have more of the practical and rudimentary language skills under one’s belt.

Note the behavior of join when the separator is an empty string…

>>> ''.join(['', '', '', '', '', '', '', ''])
>>> ''.join(['a', '', 'le'])
>>> ''.join(['a', 'le'])

That’s what I came up with too!

def count_multi_char_x(word, x):
  count = word.split(x)
  wordlen= ''.join(count)
  return (len(word)-len(wordlen ))//len(x)

can anyone validate this direction of logic? Is it on the right path or have I made a simple task more complex that it needs to be? Is there a more elegant way of doing it?