FAQ: Code Challenge: String Methods - Count Multi X

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
    else:
      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")
2
>>> 

Hi:)
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(['', '', '', '', '', '', '', ''])
'aaaaaaa'
>>> 'p'.join(['a', '', 'le'])
'apple'
>>> 'pp'.join(['a', 'le'])
'apple'
>>> 

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'])
'ale'
>>> ''.join(['a', 'le'])
'ale'
>>> 

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?

Will the following code always work this way?

splits = word.split(x)

Essentially working as a counter function for the string method?

This does not seem to work for lists.

I.E.

list1 = [1,2,3] 

list 2 = [4,5] 

for i in list2:
  count = list1.append(i) ```

Let’s set aside the count concept and focus on iterable. A split string will produce a list object. The only count, per se, is the length.

len(splits)

That line is assigning None to the variable with each iteration. There is no return from the append method.

Make it an action of its own accord, instead.

list1.append(i)

There is an easier way than append, though. Lists may be concatenated.

list1 += list2
1 Like

Well, this is very nice solution and works for words in the exercise but it wont work when you have matching (X) on the end.
As example just putting some letters together (“hajpphahsppjasjdpp”,“pp”) your code would tell us it is only 2 uses while there are 3 uses of “pp”.
I do not want to be picky i just want to show that this is not complete solution.
I had found one that uses .count() which is build-in but as @mtf mention this is not showing work and understanding.

def count_multi_char_x(word, x):
  count = 0
  for w in range(len(word)):
    if word[w : w + len(x)] == x:
      count += 1
  return count

Accepted, but:

print(count_multi_char_x("mississippi", "issi"))          # 2

If you need to count only non-overlapping strings, you’ll need to advance your iteration variable by the length of the target string each time you reach it.

You can’t do that with for, but you can with while.

1 Like

while will reduce the number of iterations, but as a brute force approach,

makes perfect sense, even while it does have to completely iterate over the word string.

>>> def count_multi_char_x(word, x):
  count = 0; c = 0
  for w in range(len(word)):
    c += 1
    if word[w : w + len(x)] == x:
      count += 1
  return count, c

>>> count_multi_char_x("mississippi", "issi")
(2, 11)
>>> 

The target does overlap (they share last/first i) though your solution still finds both impressions, which makes sense given the criteria of the problem. If we advance the iteration variable as @patrickd314 suggests, only one impression of ‘issi’ will be found in your word.

Nobody is right or wrong here. Criteria dictates must always be carefully considered, and never assumed.

We can tweak your solution slightly to eliminate unneeded iterations…

>>> def count_multi_char_x(word, x):
  count = 0; c = 0
  for w in range(len(word) - len(x)):
    c += 1
    if word[w : w + len(x)] == x:
      count += 1
  return count, c

>>> count_multi_char_x("mississippi", "issi")
(2, 7)
>>> 
2 Likes

Yes, I guess I misunderstood @web5761085078’s question:

I thought that “but” implied that 2 was an incorrect answer, and that non-overlapping instances were required. However, as it happens, the assignment is mute on whether or not overlaps are accepted.

1. Write a function named count_multi_char_x that takes a string named word and a string named x . This function should do the same thing as the count_char_x function you just wrote - it should return the number of times x appears in word . However, this time, make sure your function works when x is multiple characters long.

For example, count_multi_char_x("Mississippi", "iss") should return 2

… shoulda looked first.

2 Likes

I Have used the below solution :

def count_multi_char_x(word,x):
p = len(’’.join(word.split(x)))
l = len(word)
y = len(x)
return (l - p)/y

I thought I might approach it by iterating over the entire word by x length and look for match cases.

def count_multi_char_x(word, x):
    counter = 0
    stepper = len(x)
    #print(stepper)
    for index in range(len(word)):
        #print(index, word[index: stepper], stepper)
        if (word[index: stepper] == x):
            counter += 1
        stepper +=1
    return counter

The downside to stepping is we miss all the first letters between position one and position two. It makes sense to step past a found match, and continue from there, but until such match is found, the step should be one character over.

However, if we look back to the previous posts, we see that there are times when we would not want to jump, found match or not. The objectives need to be clear in order to choose a route to take.

Hi mtf, thank for the reply!

I am not sure I understand, because the step is one character over in word.

The function iterates over word by:
Starting at char 0 in the word and checking for matches from
Index 0 in word to len(x) in word then
Index 1 in word to len(x) in word then
Index 2 in word to len(x) in word

1 Like

For this exercise in order to get the expected result we must step one character at a time. It’s the only way we get 2 when counting issi in mississippi.

I thought that was what my function does?

1 Like

And so it does. I was letting the variable name (stepper) throw me off. My bad.