Building 'Find' function in Python - python

I have been learning Python (as my first language) from "How to Think Like a Computer Scientist: Learning with Python". This open book teaches mostly through examples and I prefer to read the goal and build the program on my own, rather than actually reading the program code provided in the book.
However, I am struggling with creating a function which will search for a specific character in a given string and return how many times that character was counted.
The code I wrote is:
def find(s, x): #find s in x
s = raw_input("Enter what you wish to find: ")
x = raw_input("Where to search? ")
count = 0
for l in x: #loop through every letter in x
if l == s:
count += 1
else:
print count
However, when I run this code, I get the error "name 's' is not defined".
The code in the book has a slightly different goal: it searches for a specific character in a string, but instead of counting how many times the character was found, it returns the position of the character in the string.
def find(strng, ch, start=0, step=1):
index = start
while 0 <= index < len(strng):
if strng[index] == ch:
return index
index += step
return -1
I don't really understand this code, actually.
However, even when I run the code, for example, to search for 'a' in 'banana', I get the error name 'banana' is not defined.
What is wrong with my code? Could please someone explain me how the code provided in the book works?

1: There are a couple things wrong with this code. The function takes in two parameters, s and x, then immediately throws them away by overwriting those variables with user input. In your for loop, every time you encounter a character that isn't s you print the count. You should try to separate different ideas in your code into different methods so that you can reuse code more easily.
Break down your code into small, simple ideas. If the purpose of find is to count the instances of a character in a string, it shouldn't also be handling user interaction. If you take out the raw_input and printing, you can simplify this function to:
def find(s, x): #find s in x
count = 0
for l in x: #loop through every letter in x
if l == s:
count += 1
return count
Now all it does it take in a character and a string and return the number of times the character appears in the string.
Now you can do your user interaction outside of the function
char = raw_input("Enter what you wish to find: ")
string = raw_input("Where to search?: )
print char + " appears " + `find(char, string)` + " times in " + string
2: The goal of this function is to find the first place where ch is found when walking through the characters strng from a starting position with a specified step. It takes in ch, strng, a position to start searching, and a step size. If the start is 0 and the step is 1, it will check every character. If the start is 2 it will check all but the first 2 characters, if the step is 2 it will check every other character, etc. This works by starting looking at the start index (index = start), then looping while the index is at least 0 and less than the length of the string. Since python is 0-indexed, the last character in the string has an index of one less than the length of the string, so this just restricts you from trying to check invalid indices. For each iteration of the loop, the code checks if the character at the current index is ch, in which case it returns the index (this is the first time it found the character). Every time it doesn't find the character at the current index, it increments the index by the step and tries again until it goes past the last character. When this happens it exits the loop and returns -1, a sentinel value which indicates that we didn't find the character in the string.
def find(strng, ch, start=0, step=1):
index = start
while 0 <= index < len(strng):
if strng[index] == ch:
return index
index += step
return -1
3: I'm guessing you passed some invalid parameters. strng should be a string, ch should be a single character, and start and step should be integers.

Try this. I took the parameters out of your function, moved the print command out of the else block and out of the for loop, and then wrote the last line to call the function.
def find(): #find s in x
s = raw_input("Enter what you wish to find: ")
x = raw_input("Where to search? ")
count = 0
for l in x: #loop through every letter in x
if l == s:
count += 1
print count
find()

It seems like you're taking in inputs s and x twice - once through the function arguments and once through raw input. Modify the function to do either one (say only from raw input - see below). Also, you only need to print out the count once, so you can place the print statement in the outermost indent level in the function.
def find(): #find s in x
s = raw_input("Enter what you wish to find: ")
x = raw_input("Where to search? ")
count = 0
for l in x: #loop through every letter in x
if l == s:
count += 1
print count

Related

Reverse a specific word function

I'm having trouble doing the next task:
So basically, I need to build a function that receives a (sentence, word, occurrence)
and it will search for that word and reverse it only where it occurs
for example:
function("Dani likes bananas, Dani also likes apples", "lik", "2")
returns: "Dani likes bananas, Dani also kiles apples"
As you can see, the "word" is 'lik' and at the second time it occurred it reversed to 'kil'.
I wrote something but it's too messy and that part still doesn't work for me,
def q2(sentence, word, occurrence):
count = 0
reSentence = ''
reWord = ''
for char in word:
if sentence.find(word) == -1:
print('could not find the word')
break
for letter in sentence:
if char == letter:
if word != reWord:
reWord += char
reSentence += letter
break
elif word == reWord:
if count == int(occurrence):
reWord = word[::-1]
reSentence += reWord
elif count > int(occurrence):
print("no such occurrence")
else:
count += 1
else:
reSentence += letter
print(reSentence)
sentence = 'Dani likes bananas, Dani also likes apples'
word = 'li'
occurrence = '2'
q2(sentence,word,occurrence)
the main problem right now is that, after it breaks it goes back to check from the start of the sentence so it will find i in "Dani". I couldn't think of a way to make it check from where it stopped.
I tried using enumerate but still had no idea how.
This will work for the given scenario
scentence = 'Dani likes bananas, Dani also likes apples'
word = 'lik'
st = word
occ = 2
lt = scentence.split(word)
op = ''
if (len(lt) > 1):
for i,x in enumerate(lt[:-1]):
if (i+1) == occ:
word = ''.join(reversed(word))
op = op + x + word
word = st
print(op+lt[-1])
Please test yourself for other scenario
This line for i,x in enumerate(lt[:-1]) basically loops on the list excluding the last element. using enumerate we can get index of the element in the list in i and value of element in x. So when code gets loops through it I re-join the split list with same word by which I broke, but I change the word on the specified position where you desired. The reason to exclude the last element while looping is because inside loop there is addition of word and after each list of element and if I include the whole list there will be extra word at the end. Hope it explains.
Your approach shows that you've clearly thought about the problem and are using the means you know well enough to solve it. However, your code has a few too many issue to simply fix, for example:
you only check for occurrence of the word once you're inside the loop;
you loop over the entire sentence for each letter in the word;
you only compare a character at a time, and make some mistakes in keeping track of how much you've matched so far.
you pass a string '2', which you intend to use as a number 2
All of that and other problems can be fixed, but you would do well to use what the language gives you. Your task breaks down into:
find the n-th occurrence of a substring in a string
replace it with another word where found and return the string
Note that you're not really looking for a 'word' per se, as your example shows you replacing only part of a word (i.e. 'lik') and a 'word' is commonly understood to mean a whole word between word boundaries.
def q2(sentence, word, occurrence):
# the first bit
position = 0
count = 0
while count < occurrence:
position = sentence.find(word, position+1)
count += 1
if position == -1:
print (f'Word "{word}" does not appear {occurrence} times in "{sentence}"')
return None
# and then using what was found for a result
return sentence[0:position] + word[::-1] + sentence[position+len(word):]
print(q2('Dani likes bananas, Dani also likes apples','lik',2))
print(q2('Dani likes bananas, Dani also likes apples','nope',2))
A bit of explanation on that return statement:
sentence[0:position] gets sentence from the start 0 to the character just before position, this is called a 'slice'
word[::-1] get word from start to end, but going in reverse -1. Leaving out the values in the slice implies 'from one end to the other'
sentence[position+len(word):] gets sentence from the position position + len(word), which is the character after the found word, until the end (no index, so taking everything).
All those combined is the result you need.
Note that the function returns None if it can't find the word the right number of times - that may not be what is needed in your case.
import re
from itertools import islice
s = "Dani likes bananas, Dani also likes apples"
t = "lik"
n = 2
x = re.finditer(t, s)
try:
i = next(islice(x, n - 1, n)).start()
except StopIteration:
i = -1
if i >= 0:
y = s[i: i + len(t)][::-1]
print(f"{s[:i]}{y}{s[i + len(t):]}")
else:
print(s)
Finds the 2nd starting index (if exists) using Regex. May require two passes in the worst case over string s, one to find the index, one to form the output. This can also be done in one pass using two pointers, but I'll leave that to you. From what I see, no one has offered a solution yet that does in one pass.
index = Find index of nth occurence
Use slice notation to get part you are interested in (you have it's beginning and length)
Reverse it
Construct your result string:
result = sentence[:index] + reversed part + sentence[index+len(word):]

How To Fix String Index Out of Range in Python

I'm currently learning python. There is an exercise in the book which outlines code for decoding. I followed along with this code however I keep getting back an error in the middle of the program.
Here is the code that is causing the problem:
def decode(string_for_decoding):
result = ""
for i in range(0, len(string_for_decoding)):
if string_for_decoding[i+1].isdigit():
result += string_for_decoding[i] * int(string_for_decoding[i+1])
elif string_for_decoding[i].isalpha():
result += string_for_decoding[i]
return result
string_for_decoding = input("Enter a string to decode: ")
print(decode(string_for_decoding))
Check if the index from range is larger than the number of chars in the string. It might look like this:
def decode(string_for_decoding: str):
result = ""
for i in range(0, len(string_for_decoding)):
if len(string_for_decoding) > i + 1 and string_for_decoding[i + 1].isdigit():
result += string_for_decoding[i] * int(string_for_decoding[i + 1])
elif string_for_decoding.isalpha():
result += string_for_decoding[i]
return result
print(decode(input("Enter a string to decode: ")))
You are going from 0 to len(string) and inside for loop you are trying to access index: i+1
THis is the root cause! Either:
iterate till one length less e.g. till len(string) - 1
Or use indices
inside appropriately
Moreover it is highly discouraged to use range(len(x)). You can simply iterate over any collective datatype as for i in x: If you want indices too have a look at enumerate(). And you can forget about index errors all together.
You are trying to get index i+1 which cannot be equal or greater than len(string).

Most frequent character in Python 3.3

This program lets the user enter a string and displays the character that appears most frequently in a string.
I need help explaining frequent = i.
# This program displays the character that appears most frequently in the string
def main():
# Local variables.
count = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
index = 0
frequent = 0
# Get input.
user_string = input('Enter a string: ')
for ch in user_string:
ch = ch.upper()
# Determine which letter this character is.
index = letters.find(ch)
if index >= 0:
# Increase counting array for this letter.
count[index] = count[index] + 1
# Please help me explain this entire part!
for i in range(len(count)):
if count[i] > count[frequent]:
frequent = i
print('The character that appears most frequently' \
' in the string is ', letters[frequent], '.', \
sep='')
# Call main
main()
The code snippet in question:
for i in range(len(count)):
if count[i] > count[frequent]:
frequent = i
First the for loop iterates over the length of count which is 26.
The if statement:
if count[i] > count[frequent]:
Checks to see if the current letter in the for loop is larger than the current most frequent character. If it is then it sets the new most frequent character as the index of the for loop.
For example,
If A is referenced 12 times and B is referenced 14 then on the second loop when i = 1 the if statement would look like this:
if 12 > 14:
frequent = 1
This sets frequent to 1 which can be used to find the frequency in count for ex.
count[1] == 14
There are 26 different items in the list count, and 26 letters in the charset. It iterates through the count list for each item (that's the for i in range (len(count)) part) and then sees if the value of that item is greater than the value of the current largest item it's found - simply speaking it finds the largest value in the array, but instead of getting the value it gets the index, frequent = i is setting the index of the largest value currently found as it iterates to the variable frequent. It's simpler and more pythonistic to simply do
frequent = index(max(count)
which has EXACTLY the same effect

How can I understand this For-Loop? (Difficulty fully understanding For-Loops)

In my Python textbook they have created a 'Hangman' game. Full source: http://pastebin.com/k1Fwp7zJ
I am having tremendous difficulty understanding the following code snippet:
new = ""
for i in range(len(word)):
if guess == word[i]:
new += guess
else:
new += so_far[i]
so_far = new
I don't know exactly what "i" is. I also don't know how to "say"/imagine the For-Loop in English. I cannot understand/imagine what is happening in this code segment, even though I've done all of the preparation in this chapter and gotten everything correct so far.
In my planning/algorithm for this part of the Hangman game, I've written:
*"Go through each character of the word and check if the guessed letter is in the word. If the guessed letter is in the word, note its position(s).
Then go to the above positions in "so_far", and replace with the guessed letter."*
I literally have a headache trying to understand this section of code. When I try to write the hangman game myself, I always get stuck here and I have no idea how to do it.
Maybe someone has been in a similar situation as me. Can someone explain what this For-loop means? And perhaps a way to understand the rest of the code here?
"I don't know exactly what i is"
i is the name to which each item in range is assigned. The first time through the loop, i == 0. The second time, i == 1, and so on.
"I don't know how to "say"/imagine the for-Loop in English."
A for loop in Python has two parts; the name(s) to assign to, and the iterable(s) to iterate through. For each value in the iterable, the loop runs once*, assigning that value to the provided name.
Your example is a relatively simple one:
for i in range(...):
Here range(start[, stop[, step]]) provides the integers in each step from start to stop (not inclusive). You have only a stop, so the default start=0 and step=1 are used, giving:
range(n) ~= [0, 1, 2, ..., n-1, n]
Each of these values in assigned, in turn, to the name i, allowing you to access them inside the loop.
* unless you break out, return or an error is raised
new = ""
This line creates an empty string
for i in range(len(word)):
In this line the code tells the interpreter for every number in the range 0 up to the length (obtained by the len() funciton) of word -1 do the code that follows.
For example len('Thing') would be 5. Now the interpreter will do whatever is inside the for loop 5 times if the code was:
for i in range(len('thing')):
print('Hello, world')
Hello, world would be printed 5 times. In Python you don't need to increment i like you do in other languages. So when the loop starts i == 0 after it goes through the if/else block it will be incremented to 1 automatically.
if guess == word[i]:
This line checks to see if the variable guess is equal to the value of word at index i. For example if word = 'thing' then word[0] would be t. Computers start counting from 0 not 1, so word[4] would be g.
new += guess
This line is shorthand for new = new + guess. Since we are working with strings the + operator wil concatenate them, or glue them together. For example 'a' + 'b' would be ab.
else:
This line indicates what to do if the if condition is not met. For example:
if some_number > 10:
print('hello')
else:
print('Bye')
If some_number was greater than 10 hello would print. If not Bye would print.
new += so_far[i]
This line concatenates new and whatever is at index i in so_far.
so_far = new
This sets so_far equal to new.
In your program, Python's range() function takes an integer (here, the length of the word you're trying to guess) and returns a list of integers from 0 to that number.* So:
word = "example"
len(word) //equals 7
range(len(word)) //returns [0,1,2,3,4,5,6]
Lists in Python are iterable data types. This means that you can iterate over the elements, i.e. move over the elements one at a time and do something to each one. First it sets i to 0, then does whatever is contained in the body of the for-loop. Then it sets i to 1 and does whatever is contained in the body of the for loop again. And it keeps going until it reaches the end of the list. So with your example:
word = "example"
for i in range(len(word))
You're telling Python to do something on each element i in the list [0,1,2,3,4,5,6]. There's nothing special about "i" here. You can name it whatever you want, but it's just a conventional shorthand notation used to reference the element later. For example:
for i in range(3):
print "The number is " + i
This prints:
The number is 0
The number is 1
The number is 2
In Python, strings can be accessed by index. So for example:
word = "example"
word[0] = "e"
word[1] = "x"
. . .
Couple this with the for-loop, and you have:
word = "example"
myWordLength = len(word)
for i in range(myWordLength):
print "The letter is " + word[i]
And this with print:
The letter is e
The letter is x
The letter is a
The letter is m
The letter is p
The letter is l
The letter is e
Range(), for-loops and lists can do lots of other things too but hopefully that helps you understand the assignment.
for loops follow this simple design:
Let's break this line down:
for i in range(len(word)):
First, let's look at:
for i
The keyword for is known as a loop. It will repeat/iterate the same chunk of code until the condition is met. The i is the current variable(in this case, numeric variable). Imagine someone say, write the numbers from 1 to 10, then your i will go from the number 1 to the number 10.
in
The keyword in will be declaring the range of values the previous variable i will equal. Let's break down this:
range(len(word))
This translate to the range values of the length of the variable word. Say the the word equals to "hello", then length is 5. This means the range of 5 is 0,1,2,3,4 (range excludes the final value).
Basically, this:
for i in range(len(word)):
Means:
iterate the variable `i` from the range of the length of the the variable `word`.
A simple test to see what i is to change the code to:
new = ""
for i in range(len(word)):
print i #this will print the values
if guess == word[i]:
new += guess
else:
new += so_far[i]
so_far = new
Remember, there are plenty of tutorials online:
Link 1
Link 2
Link 3

Find method with empty string

I was playing around with a function for an assignment just to better understand it. It was meant to find the last occurrence of a sub-string within a string. The function should return the position of the start of the last occurrence of the sub-string or it must return -1 if the sub-string is not found at all. The 'standard' way was as follows:
def find_last(full, sub):
start = -1
while True:
new = full.find(sub, start + 1)
if new == -1:
break
else:
start = new
return start
I wanted to try and have it search in reverse, as this seemed to be the more efficient way. So I tried this:
def find_last(full, sub):
start = -1
while True:
new = full.find(sub, start)
if new == -1 and abs(start) <= len(full): #evals to False when beginning of string is reached
start -= 1
else:
break
return new
We were given a handful of test cases which needed to be passed and my reversed function passed all but one:
print find_last('aaaa', 'a')
>>>3
print find_last('aaaaa', 'aa')
>>>3
print find_last('aaaa', 'b')
>>>-1
print find_last("111111111", "1")
>>>8
print find_last("222222222", "")
>>>8 #should be 9
print find_last("", "3")
>>>-1
print find_last("", "")
>>>0
Can someone kindly explain why find is behaving this way with negative indexing? Or is it just some glaring mistake in my code?
The empty string can be found at any position. Initializing start with -1 makes your algorithm beginning its search at the penultimate position, not the last.
The last position is after the last character of the string, but you are starting to look at the last character of the string.

Categories

Resources