string index out of range in Python - python

I want to find how many times an character repeated in a word for example: how many times the 'l' repeated in the "Hello". but it drops me this error:
IndexError: string index out of range
And my code:
def fin(x,lst):
if x == '':
return 0
if lst[0] == x:
return 1+ fin(x,lst[1:])
else:
return fin(x,lst[1:])

There are pre-written functions in python to do this for you. But if you're doing this for the sake of education...
You have the wrong stop condition, you should be checking if the lst is empty, not x

Related

When asked to write function for multiple of 3, why do i keep getting errors?

When I'm asked to write in my function a code to count the characters of a code but only if its a multiple of three, i keep getting stuck and i've tried so many times to figure it out but to no avail!
This was the question: ...verifies that its length is a multiple of 3, and returns the number of codons in that string...
I tried this:
def countCodons(DNA):
count = 0
for num in DNA:
if len(num) % 3 == 0:
count += 1
return len(DNA)
else:
return False
assert countCodons("CATGGG") == 2
assert countCodons("CAATGGG") == False
But I keep getting an error. When i just put in "countCodons" I keep getting False.
You are making this too complicated. The function needs to do two things:
determine if the length of the input string is a multiple of 3
if so, return the length of the input string divided by 3
You were right in assuming that you can use ... % 3 == 0 somehow but you were not applying it correctly. You don't need a for loop, which iterates over the individual characters in the string. Just apply it on the length of the string directly.
Regarding 2., even if you had managed to count the characters in the input string, you forgot to divide by 3.
Here's a straightforward solution:
def countCodons(DNA):
if len(DNA) % 3 == 0: # length is a multiple of 3
return len(DNA) // 3
else:
return False
Note that // is used to return an integer result, rather than a floating-point result (see Python Tutorial).
Alternatively you could use the divmod function which combines the integer division with remainder in one step:
def countCodons(DNA):
count, remainder = divmod(len(DNA), 3)
if remainder == 0:
return count
else:
return False
This assertion fails because the return statement is within the loop and only returns the length of the input string, not the count of codons. So, it will always return the length of the input string, even if there are no codons in the input string.
assert countCodons("CAATGGG") == False
This assertion succeeds because the first element in the input string is not a multiple of 3, so the function returns False.
To fix this issue, the return statement should be outside the loop and return the count of codons. Here's the corrected code:
def countCodons(DNA):
count = 0
for num in DNA:
if len(num) % 3 == 0:
count += 1
return count if count > 0 else False
This code will now correctly return the count of codons in the input string.

How do I find a substring in a string using recursion only?

So here is my code
def count_occurrences(sub, s):
if len(s) == 0:
return 0
else:
if str(sub) in str(s) and str(sub) == str(s):
return 1+count_occurrences(sub, s[1:])
else:
return count_occurrences(sub, s[1:])
print(count_occurrences('ill', 'Bill will still get ill'))
I believe this if str(sub) in str(s) and str(sub) == str(s): statement is throwing me off when I run the debugger UI. If I just put if str(sub) in str(s) it gives me a number but it is not the number I want which is 4.
Your code didn't quite work properly because you skipped one character only if you found the substring that will lead the program to find the substring at the same place, instead you have to skip to the index after the first occurence of the substring. This code will work
def count_occurences(s, sub):
if len(s) == 0:
return 0
else:
ind = s.find(sub)
if ind>=0:
return 1+count_occurences(s[ind+1:], sub)
else:
return 0
I added 1 to the index because, in the case of "ill", find() will give me the index of the letter 'i', so if I give s[ind+1:] that will remove all the characters before the first 'l' i.e including 'i', so the next iteration won't find "ill" in the same place as before which leads to counting the same occurence twice.
your condition str(sub) == str(s) will never be True, except maybe if the substring is at the very end. You have to compare the start of the string (same length as the substring) instead of searching for it at any position, otherwise you'll count the same match multiple times. Also, you dont need to use str() if you are already processing strings.
def count_occurrences(sub, s):
if len(sub)>len(s): return 0
return s.startswith(sub) + count_occurrences(sub,s[1:]) # True is 1
Output:
print(count_occurrences('ill', 'Bill will still get ill'))
4
Note that I assumed that you want to count overlapping substrings. For example: 'ana' counts for 2 in 'banana'.

How to make a for loop iterate through each item in a string with an if statement?

I'm trying to make a function that takes in a string from a user and then outputs the same string. However for each letter in an even position it outputs the corresponding lower case letter, and for each letter in an odd position it outputs the corresponding uppercase letter. Keep in mind only one word will be passed through it at a time.
I've tried to create a for loop with an if statement nested within it, but so far, the for loop stops after iterating through the first letter. My code is below:
def converter(string):
for letters in string:
if len(letters) % 2 == 0:
return letters.lower()
elif len(letters)% 2 != 0:
return letters.upper()
When I run the code:
converter('app')
The output I get is 'A'
The expected output should be 'aPp'
The first thing you need to know is that in Python, strings are immutable. So "modifying" a string means you have to build a new string from scratch in (here, I call that newstring).
Second, you are misunderstanding the loop. You are saying for letters in string. This loop iterates over each letter of the string. On the first iteration, letters is the first letter of the strong. You then convert it to upper case (since the length of a single letter is always 1), and return it. You aren't reaching the rest of the letters! In the code below, I change the plurality to just letter to make this idea clear.
This amends all of those problems:
def converter(string):
newstring = ""
for i, letter in enumerate(string):
if i % 2 == 0:
newstring += letter.lower()
elif i % 2 != 0:
newstring += letter.upper()
return newstring
This can be boiled down to a nice list comprehension:
def converter(string):
return "".join([letter.lower() if i % 2 == 0 else letter.upper()
for i, letter in enumerate(string)])
In [1]: def converter(string):
...: return ''.join([j.upper() if i % 2 == 1 else j.lower() for i, j in enumerate(string)])
In [2]: converter('apple')
Out[2]: 'aPpLe'
''.join([s.lower() if c % 2 == 0 else s.upper() for c, s in enumerate('apple')])
# returns 'aPpLe'
first check for the condition, then iterate through the string using the nice old enumerate built-in.

How can I figure out what this Python code does?

I am learning Python and I'd like to know what this code does.
# This code is supposed to get an input of a word and not a sentence
def do_something(word):
index = len(word)/2
len_word = len(word)
if index == 0:
return True
elif len_word % 2 == 0:
return word[0:index] == word[-1:index-1:-1]
else:
return word[0:index+1] == word[-1:index-1:-1]
Now I tried to check but the variable index doesn't work to me maybe because I am using 3.7.
But I checked it without using the variable and just counting it and I think this code suppose to check if the first half is equal to the second half backwards or something like that.
And I am also not sure why there is this line:
if index == 0:
return True
Would someone explain it?
This code defines a function. The function does not run. It is apparently intended to check if it's a palindrome
If you ran the function it would return a boolean value of True or False based on the word.
index is defined as len(word)/2 (or len(word)//2 as mentioned in the comments) so it is apparently intended to catch the case where word is something like ""
The next elif checks if word is of even length. The code to check for a palindrome needs to be adjusted based on this. Hence the slight difference in return codes between the elif and else
return word[0:index] == word[-1:index-1:-1] (from the elif as an example) gets the first half of the word as word[0:index] and the second half in reverse by word[-1:index-1:-1] to check if they are identical. It reverses the second half of the word with that -1 at the end of the slicing.
if index == 0:
return True
Checks if the input is only 1 word. Like 1//2 == 0 but 2 or more is not equals to 0.
elif len_word % 2 == 0:
return word[0:index] == word[-1:index-1:-1] # will return True or False
If the length is even(2,4,6...) then compare characters of the string from 0 to index with characters of the string from the end till index-1 and if matchesreturn TrueotherwiseFalse`
return word[0:index+1] == word[-1:index-1:-1]
If the length is odd(1,3,5...) then compare characters of the string from 0 to index+1 with characters of the string from the end till index-1 and if matchesreturn TrueotherwiseFalse`.
Note: there is a mistake in the code index = len(word)/2 should have been with double slash index = len(word)//2. One slash is float dividing and will return 0.5 so the first case will never be true(index == 0).

Count vowels from raw input

I have a homework question which asks to read a string through raw input and count how many vowels are in the string. This is what I have so far but I have encountered a problem:
def vowels():
vowels = ["a","e","i","o","u"]
count = 0
string = raw_input ("Enter a string: ")
for i in range(0, len(string)):
if string[i] == vowels[i]:
count = count+1
print count
vowels()
It counts the vowels fine, but due to if string[i] == vowels[i]:, it will only count one vowel once as i keeps increasing in the range. How can I change this code to check the inputted string for vowels without encountering this problem?
in operator
You probably want to use the in operator instead of the == operator - the in operator lets you check to see if a particular item is in a sequence/set.
1 in [1,2,3] # True
1 in [2,3,4] # False
'a' in ['a','e','i','o','u'] # True
'a' in 'aeiou' # Also True
Some other comments:
Sets
The in operator is most efficient when used with a set, which is a data type specifically designed to be quick for "is item X part of this set of items" kind of operations.*
vowels = set(['a','e','i','o','u'])
*dicts are also efficient with in, which checks to see if a key exists in the dict.
Iterating on strings
A string is a sequence type in Python, which means that you don't need to go to all of the effort of getting the length and then using indices - you can just iterate over the string and you'll get each character in turn:
E.g.:
for character in my_string:
if character in vowels:
# ...
Initializing a set with a string
Above, you may have noticed that creating a set with pre-set values (at least in Python 2.x) involves using a list. This is because the set() type constructor takes a sequence of items. You may also notice that in the previous section, I mentioned that strings are sequences in Python - sequences of characters.
What this means is that if you want a set of characters, you can actually just pass a string of those characters to the set() constructor - you don't need to have a list one single-character strings. In other words, the following two lines are equivalent:
set_from_string = set('aeiou')
set_from_list = set(['a','e','i','o','u'])
Neat, huh? :) Do note, however, that this can also bite you if you're trying to make a set of strings, rather than a set of characters. For instance, the following two lines are not the same:
set_with_one_string = set(['cat'])
set_with_three_characters = set('cat')
The former is a set with one element:
'cat' in set_with_one_string # True
'c' in set_with_one_string # False
Whereas the latter is a set with three elements (each one a character):
'c' in set_with_three_characters` # True
'cat' in set_with_three_characters # False
Case sensitivity
Comparing characters is case sensitive. 'a' == 'A' is False, as is 'A' in 'aeiou'. To get around this, you can transform your input to match the case of what you're comparing against:
lowercase_string = input_string.lower()
You can simplify this code:
def vowels():
vowels = 'aeiou'
count = 0
string = raw_input ("Enter a string: ")
for i in string:
if i in vowels:
count += 1
print count
Strings are iterable in Python.
for i in range(0, len(string)):
if string[i] == vowels[i]:
This actually has a subtler problem than only counting each vowel once - it actually only tests if the first letter of the string is exactly a, if the second is exactly e and so on.. until you get past the fifth. It will try to test string[5] == vowels[5] - which gives an error.
You don't want to use i to look into vowels, you want a nested loop with a second index that will make sense for vowels - eg,
for i in range(len(string)):
for j in range(len(vowels)):
if string[i] == vowels[j]:
count += 1
This can be simplified further by realising that, in Python, you very rarely want to iterate over the indexes into a sequence - the for loop knows how to iterate over everything that you can do string[0], string[1] and so on, giving:
for s in string:
for v in vowels:
if s == v:
count += 1
The inner loop can be simplified using the in operation on lists - it does exactly the same thing as this code, but it keeps your code's logic at a higher level (what you want to do vs. how to do it):
for s in string:
if s in vowels:
count += 1
Now, it turns out that Python lets do math with booleans (which is what s in vowels gives you) and ints - True behaves as 1, False as 0, so True + True + False is 2. This leads to a one liner using a generator expression and sum:
sum(s in vowels for s in string)
Which reads as 'for every character in string, count how many are in vowels'.
you can use filter for a one liner
print len(filter(lambda ch:ch.lower() in "aeiou","This is a String"))
Here's a more condensed version using sum with a generator:
def vowels():
string = raw_input("Enter a string: ")
print sum(1 for x in string if x.lower() in 'aeiou')
vowels()
Option on a theme
Mystring = "The lazy DOG jumped Over"
Usestring = ""
count=0
for i in Mystring:
if i.lower() in 'aeiou':
count +=1
Usestring +='^'
else:
Usestring +=' '
print (Mystring+'\n'+Usestring)
print ('Vowels =',count)
The lazy DOG jumped Over
^ ^ ^ ^ ^ ^ ^
Vowels = 7

Categories

Resources