Looping and Counting w/find - python

So I am working diligently on some examples for my homework and came across yet another error.
The original:
word = 'banana'
count = 0
for letter in word:
if letter == 'a':
count = count + 1
print count
Ok. Looks simple.
I then used this code in a function name count and generalized it so that it accepts the string and the letter as argument.
def count1(str, letter):
count = 0
word = str
for specific_letter in word:
if specific_letter == letter:
count = count + 1
print count
This is where I'm still not sure what I'm doing wrong.
I have to rewrite this function so that instead of traversing the string, it uses the three-parameter version of find from the previous section. Which this is:
def find(word, letter, startat):
index = startat
while index <= len(word):
if word[index] == letter:
return index
index = index + 1
return -1
This is how far I got... but the program doesn't work the way I want it to.
def find(str, letter, startat):
index = startat
word = str
count = 0
while index <= len(word):
if word[index] == letter:
for specific_letter in word:
if specific_letter == letter:
count = count + 1
print count
index = index + 1
Can someone point me in the right direction. I want to understand what I'm doing instead of just given the answer. Thanks.

The point of the exercise is to use the previously defined function find as a building block to implement a new function count. So, where you're going wrong is by trying to redefine find, when you should be trying to change the implementation of count.
However, there is a wrinkle in that find as you have given has a slight error, you would need to change the <= to a < in order for it to work properly. With a <=, you could enter the body of the loop with index == len(word), which would cause IndexError: string index out of range.
So fix the find function first:
def find(word, letter, startat):
index = startat
while index < len(word):
if word[index] == letter:
return index
index = index + 1
return -1
And then re-implement count, this time using find in the body:
def count(word, letter):
result = 0
startat = 0
while startat < len(word):
next_letter_position = find(word, letter, startat)
if next_letter_position != -1:
result += 1
startat = next_letter_position + 1
else:
break
return result
if __name__ == '__main__':
print count('banana', 'a')

The idea is to use find to find you the next index of the given letter.
In your code you don't use the find function.

If you want to try something interesting and pythonic: Change the original find to yield index and remove the final return -1. Oh, and fix the <= bug:
def find(word, letter, startat):
index = startat
while index < len(word):
if word[index] == letter:
yield index
index = index + 1
print list(find('hello', 'l', 0))
Now find returns all of the results. You can use it like I did in the example or with a for position in find(...): You can also simply write count in terms of the length of the result.
(Sorry, no hints on the final function in your question because I can't tell what you're trying to do. Looks like maybe you left in too much of the original function and jumbled their purposes together?)

Here's what I came up with: This should work.
def find(word, letter, startat)
index = startat
count = 0
while index < len(word):
if word[index] == letter:
count = count + 1 ##This counts when letter matches the char in word
index = index + 1
print count
>>> find('banana', 'a', 0)
3
>>> find('banana', 'n', 0)
2
>>> find('mississippi', 's', 0)
4
>>>

Try using :
def find_count(srch_wrd, srch_char, startlookingat):
counter = 0
index = startlookingat
while index < len(srch_wrd):
if srch_wrd[index] == srch_char:
counter += 1
index += 1
return counter`

def count_letter2(f, l):
count = 0
t = 0
while t < len(f):
np = f.find(l, t)
if np != -1:
count += 1
t = np + 1
"I was wrong by doing t =t +1"
else:
break
return count
print(count_letter2("banana", "a"))
print(count_letter2("abbbb", "a"))

Related

finding the most amount of times a substring appears successively in a string

I have a long string of characters and not only am I trying to find if a substring of those characters exists within the larger string, I'm also trying to find the longest run of successive instances.
For example... in the code snippet below I've found that I can use "count" to see how many times the substring b appears in a. That result is 5. However, what I'm trying to identify is the longest successive run, which would be 3 (where 'abc' appears back to back to back in the middle). I'm having difficulty running through the logic of this one. Any advice would be appreciated.
a = "abcxyzabcabcabcxyzabcxyz"
b = "abc"
total = a.count(b)
print(total)
This should be fairly simple with a while loop:
def func(a, b):
n = 1
while b*n in a:
n += 1
return n - 1
One possible and naive solution is to use the python index function to identify the closest index of the substring. From there you can simply continue searching ahead for the substring until you find a point where it doesnt appear anymore, then call index again to skip ahead.
Example:
a = "abcxyzabcabcabcxyzabcxyz"
b = "abc"
curr_index = a.index(b)
longest_count = 0
current_count = 0
while curr_index < len(a):
if a[curr_index : curr_index + len(b)] == b:
curr_index += len(b)
current_count += 1
else:
if longest_count < current_count:
longest_count = current_count
try:
curr_index = a.index(b, curr_index)
except ValueError:
# Substring no longer found in string slice
break
current_count = 0
if longest_count < current_count:
longest_count = current_count
print(longest_count)
This just returns the longest repeating count, but it doesn't return the location where it starts. Adding that functionality, however, is trivial.
Keep calling a.index on b with the appropriate indices. If the index is the start of your subset, you're in the same run. Otherwise, start a new run:
def longest_run(string, pattern):
longest = 0
current = 0
start = 0
while True:
try:
ind = string.index(pattern, start)
if ind == start:
current += 1
else:
if current > longest:
longest = current
current = 1
start += len(pattern)
except ValueError:
return longest
You can use re.findall with a pattern that matches one or more times of b (use re.escape to prevent b from being interpreted as regex), then map the returning strings to len and pass them to max to obtain the length of the longest match, and then divide that length by the length of b to get the number of times b is repeated:
import re
max(map(len, re.findall('(?:%s)+' % re.escape(b), a))) // len(b)

couldn't figure out the string count behaviour in certain input

string = input("Enter the string: ")
sub_string = input("Enter sub string: ")
count = 0
idx = 0
while string.count(sub_string, idx) != 0:
count += string.count(sub_string, idx)
idx = string.index(sub_string, idx)
idx += 1
if string.count(sub_string, idx) == 0:
print(count)
break
when i give this code input as follows:
ininini
ini
It prints output 4. I tried running debugger and found out that it is incrementing count with +2 in the first step instead of +1 and I couldn't figure out that. Any suggestions would be very much helpful.
Use:
count += 1
instead of
count += string.count(sub_string, idx)
string.count(sub_string, idx) is 2 initially, and that's why you end up adding 2 in first iteration (instead of intended 1), thereby getting a 1 more than expected.
What you need is to increment count by 1 in every iteration and if you make this change, you get 3 as output.
I would use a for loop instead:
string = input("Enter the string: ")
sub_string = input("Enter sub string: ")
count = 0
for index in range(len(string) - len(sub_string) + 1):
if string[index: index + len(sub_string)] == sub_string:
count += 1
print(count)
If you are tyring to reach to get the length of the string, just use
len(string)

Counting occurrences of a sub-string without using a built-in function

My teacher challenged me of finding a way to count the occurences of the word "bob" in any random string variable without str.count(). So I did,
a = "dfjgnsdfgnbobobeob bob"
compteurDeBob = 0
for i in range (len(a) - 1):
if a[i] == "b":
if a[i+1] == "o":
if a[i+2] == "b":
compteurDeBob += 1
print(compteurDeBob)
but I wanted to find a way to do that with a word of any length as shown below, but I have no clue on how to do that...
a = input("random string: ")
word = input("Wanted word: ")
compteurDeBob = 0
for i in range (len(a)-1):
#... i don't know...
print(compteurDeBob)
a = input("random string: ")
word = input("Wanted word: ")
count = 0
for i in range(len(a)-len(word)):
if a[i:i+len(word)] == word:
count += 1
print(count)
If you want your search to be case-insensitive, then you can use lower() function:
a = input("random string: ").lower()
word = input("Wanted word: ").lower()
count = 0
for i in range(len(a)):
if a[i:i+len(word)] == word:
count += 1
print(count)
For the user input
Hi Bob. This is bob
the first approach will output 1 and the second approach will output 2
To count all overlapping occurrences (like in your example) you could just slice the string in a loop:
a = input("random string: ")
word = input("Wanted word: ")
cnt = 0
for i in range(len(a)-len(word)+1):
if a[i:i+len(word)] == word:
cnt += 1
print(cnt)
You can use string slicing. One way to adapt your code:
a = 'dfjgnsdfgnbobobeob bob'
counter = 0
value = 'bob'
chars = len(value)
for i in range(len(a) - chars + 1):
if a[i: i + chars] == value:
counter += 1
A more succinct way of writing this is possible via sum and a generator expression:
counter = sum(a[i: i + chars] == value for i in range(len(a) - chars + 1))
This works because bool is a subclass of int in Python, i.e. True / False values are considered 1 and 0 respectively.
Note str.count won't work here, as it only counts non-overlapping matches. You could utilise str.find if built-ins are allowed.
The fastest way to calculate overlapping matches is the Knuth-Morris-Pratt algorithm [wiki] which runs in O(m+n) with m the string to match, and n the size of the string.
The algorithm first builds a lookup table that acts more or less as the description of a finite state machine (FSM). First we construct such table with:
def build_kmp_table(word):
t = [-1] * (len(word)+1)
cnd = 0
for pos in range(1, len(word)):
if word[pos] == word[cnd]:
t[pos] = t[cnd]
else:
t[pos] = cnd
cnd = t[cnd]
while cnd >= 0 and word[pos] != word[cnd]:
cnd = t[cnd]
cnd += 1
t[len(word)] = cnd
return t
Then we can count with:
def count_kmp(string, word):
n = 0
wn = len(word)
t = build_kmp_table(word)
k = 0
j = 0
while j < len(string):
if string[j] == word[k]:
k += 1
j += 1
if k >= len(word):
n += 1
k = t[k]
else:
k = t[k]
if k < 0:
k += 1
j += 1
return n
The above counts overlapping instances in linear time in the string to be searched, which was an improvements of the "slicing" approach that was earlier used, that works in O(m×n).

Alternating letter in python

def myfunc(word):
result = ""
index = 0
for letter in word:
if index % 2 == 0:
result += letter.lower()
else:
result += letter.upper()
return result
index +=1
I am trying to return a matching string where every even letter is uppercase and every odd letter is lowercase. But the code doesn't show this exact result, any solution?
The problem is that you're only incrementing index after the loop, rather than each time through it. So, inside the loop, it's always 0. The smallest fix is:
def myfunc(word):
result = ""
index = 0
for letter in word:
if index % 2 == 0:
result += letter.lower()
else:
result += letter.upper()
index += 1
return result
But this kind of mistake is very easy to make (and sometimes not as easy as this to debug)—which is exactly why Python has nice tools like enumerate, that make it impossible to get wrong:
def myfunc(word):
result = ""
for index, letter in enumerate(word):
if index % 2 == 0:
result += letter.lower()
else:
result += letter.upper()
return result
People, including myself, have already pointed out your programming error. Here is an alternative one-liner solution to your problem using a generator expression and a ternary conditional operator:
def myfunc(word):
return "".join(w.upper() if i%2 else w.lower() for i,w in enumerate(word))
enumerate will return a tuple of the form (index, value) for each item in the iterable. In this case, the iterable is the string word.
At each step in the iteration, we check to see if the index i is odd.
i%2 will return 0 for even numbers and the if statement will evaluate to False.
Likewise, it will evaluate to True for odd numbers.
Respectively, we call lower() and upper() on the current character w.
Finally we use str.join to concatenate all the individual letters back together. Here we join the characters using an "" with is the empty string.
The problem was with how you were incrementing. You only set up your index to increment inside the "Else" block of your code. It was missing from the "If" block. As such as soon as you entered the "If" block you would be stuck there.
def myfunc(string):
result = ""
index = 0
for letter in string:
if index % 2 == 0:
result += letter.upper()
index += 1
else:
result += letter.lower()
index += 1
return result
def myfunc(word):
result = ""
for index, letter in enumerate(word):
if index % 2 == 0:
result += letter.lower()
else:
result += letter.upper()
return result
this worked for me.
Also it is much easier to understand the above block of code if you understand the enumerate function well
def myfunc(word):
index = 0
result = ''
for letter in word:
if index % 2 == 0:
result += letter.lower()
else:
result += letter.upper()
index += 1
print result
You weren't increment your index in the correct spot ;)
If you execute myfunc(word) it will print hElLo
def gonna(st) :
a = []
Index = 0
for index, c in enumerate(st) :
if index ℅ 2 == 0:
a.append(c.upper())
Index = Index + 1
else:
a.append(c.lower())
Index = Index + 1
return a
def myfunc(a):
result=""
for x in range(0,len(a)):
if x%2==0:
result=result+a[x].upper()
else:
result=result+a[x].lower()
return result
def myfunc(word):
z=list(word)
x=[]
y=[]
new_list=[]
str=""
for a in z:
x+=[a]
if len(x)==2:
y+=[x]
x=[]
for i in y:
odd=i[0].lower()
even=i[1].upper()
new_list.append(odd)
new_list.append(even)
for el in new_list:
str+=el
return str
def myfunc(str):
# Create an empty string to append the values to
result = ''
# Iterate through the loop using the enumerate function on the string so that you can use the index and the letter at the same time.
for index,letter in enumerate(str):
if index %2 == 0:
result += letter.lower()
else:
result += letter.upper()
# Return the string after all the letters have been appended to the string
return result
More Simpler , which is made using all the basic conecpts of Python
def myfunc(string):
new_string=""
for items in range(len(string)): # help us to to know about the index
if items % 2 == 0:
new_string = new_string + string[items].upper()
else:
new_string = new_string + string[items].lower()
return new_string
result=myfunc("Draco")
print(result)
def myfunc(word):
index=0
result = ''
for letter in word:
if index%2==0:
result=result+letter.upper()
else:
result=result+letter.lower()
index+=1
return result
**
Heading
**
def myfunc(word):
result = ""
for index, letter in enumerate(word):
if index % 2 == 0:
result += letter.upper()
else:
result += letter.lower()
return result

count an occurrence of a string in a bigger string

I am looking to understand what I can do to make my code to work. Learning this concept will probably unlock a lot in my programming understanding. I am trying to count the number of times the string 'bob' occurs in a larger string. Here is my method:
s='azcbobobegghakl'
for i in range(len(s)):
if (gt[0]+gt[1]+gt[2]) == 'bob':
count += 1
gt.replace(gt[0],'')
else:
gt.replace(gt[0],'')
print count
How do I refer to my string instead of having to work with integers because of using for i in range(len(s))?
Try this:
def number_of_occurrences(needle, haystack, overlap=False):
hlen, nlen = len(haystack), len(needle)
if nlen > hlen:
return 0 # definitely no occurrences
N, i = 0, 0
while i < hlen:
consecutive_matching_chars = 0
for j, ch in enumerate(needle):
if (i + j < hlen) and (haystack[i + j] == ch):
consecutive_matching_chars += 1
else:
break
if consecutive_matching_chars == nlen:
N += 1
# if you don't need overlap, skip 'nlen' characters of 'haystack'
i += (not overlap) * nlen # booleans can be treated as numbers
i += 1
return N
Example usage:
haystack = 'bobobobobobobobobob'
needle = 'bob'
r = number_of_occurrences(needle, haystack)
R = haystack.count(needle)
print(r == R)
thanks. your support help to birth the answer in. here what I have :
numBobs = 0
for i in range(1, len(s)-1):
if s[i-1:i+2] == 'bob':
numBobs += 1
print 'Number of times bob occurs is:', numBobs

Categories

Resources