I am wondering how to count specific letters in a string. The first thing that popped into my head was the function len. Out of curiosity, is there a way to write this code without using built in functions and using len?
There is a question asked similar to this here and I am having trouble understanding it.
def count_letters(word, char):
count = 0
for c in word:
if char == c:
count = count + 1
return count
What exactly is going on in if char == c: and count += 1? I understand why the person started with a for loop but I don't understand why place an if after?
The if is needed because you only want to count instances of a specific character, char. Without it, you would wind up doing count = count + 1 for every character in the string, so you'd get the full string length, not the amount of specific character you're looking for.
With comments in code:
for c in word: # go through each character in code
if char == c: # if the character is the one we're counting
count = count + 1 # add one to the current count of characters
Strings have a built in count() method:
>>> s = 'aaabbbccc'
>>> s.count('a')
3
>>> s.count('aa')
1
Have you tried the Python Wiki?
It states that ANY object with an iterating function can be cycled through, which answers your second question.
Since you don't want to use the len function, you can use the for loop like in the answer you linked to cycle through the object (the String word) looking for the character char, recording each time the char is found with count.
The parameter char needs to be found in word parameter, and so c is just a variable to set to each letter (or character, not all parts of the String may be an alphabetical letter) as it cycles through word.
The reason for the if statement is so when the cycling variable c equals char, the block can be executed. In this particular block, the count is being iterated up (count = count + 1), and once the function is done with iterating through the for loop, it will return count (how many times char was found, effectively counting specific letters in the String as you asked for).
Long-winded but in short, yes, that function you posted will give you a count of how many times the letter is in the word.
You want to count only for specific char. Meaning that if you have the word "hello" and the letter "l", you want to return 2 because "l" appears 2 times in "hello".
The if simply checks if the char is the char you want, if that's the case, you increment the counter by one - for c in word: iterates on the chars of word.
Python's syntax is very readable and easy to understand, try to speak the code and you'll understand what it does.
Another way to do that is:
print len([c for c in word if c == char])
Example:
[c for c in 'hello world' if c == 'l']
Will return:
['l', 'l', 'l']
Then len will return 3.
Using collections.Counter
>>> word = "Hallelujahhhhh"
>>> from collections import Counter
>>> Counter(word)
Counter({'h': 5, 'l': 3, 'a': 2, 'e': 1, 'H': 1, 'j': 1, 'u': 1})
for c in word:
In this statement word will be taken as a list of a string, c is each character from that list. That means loop will repeat for each character of the word.
So in this statement if char == c: for every character of word will be compare with char.
If the statement is true then count will increase by 1.
So, As per your question
if char == c: compare char with each character of word
and
count+=1 will increase the value of count by 1
Related
The task was to write a function with name count_letter that takes a list of words and certain letter and returns amount of words where this letter is found at least once. And, we have to use a for loop.
So I did a list of some programming languages and letter "a", and tried to apply everything we learned so far plus some internet tutorials to understand how to translate human logic into lines of code, but obviously I am missing something, because it doesn't work :(
That is how my code looks like at the moment:
mylist = ['fortran', 'basic', 'java', 'python', 'c++']
letter = 'a'
a_list = []
def count_letter(mylist):
count = 0
for i in range(len(mylist)):
if letter in i:
count += 1
a_list.append(i)
return a_list
print(len(a_list))
Result is - no result. Online-python compiler returns response ** process exited - return code: 0 **
My question is - what could I miss or positioned wrongly that loop doesn't work. I want to understand it for myself.
In tutorials I have found one construction which returns correct answer (and looks very elegant and compact), but it has no function, so it is not really what we needed to write:
mylist = ['fortran', 'basic', 'java', 'python', 'c++']
letter = 'a'
res = len ([ele for ele in mylist if letter in ele])
print ('Amount of words containing a: ' +str(res))
Here system response: 3 , as expected.
Please tell me what should I check in code #1.
Few mistakes I found in your code:
When you do for i in range(len(mylist)), you are actually looping through the numbers 1,2,... instead of elements of mylist. So you have to use "for i in mylist" to loop through elements of the array mylist.
When you return from a function, the code that is after the return is not executed. So you have to print it first and then return from the function.
Don't forget to call the function. Otherwise the function won't be executed.
No need count variable as you can access the length using len method.
mylist = ['fortran', 'basic', 'java', 'python', 'c++']
letter = 'a'
a_list = []
def count_letter(mylist):
for i in mylist:
if letter in i:
a_list.append(i)
print(len(a_list))
return a_list
print(count_letter(mylist))
All the best in your journey!
Personally, I find Python source code easier to read when things are indented by four spaces. So, here is your function again with a wider indentation:
def count_letter(mylist):
count = 0
for i in range(len(mylist)):
if letter in i:
count += 1
a_list.append(i)
return a_list
print(len(a_list))
for i in range(...) will iterate over a collection of integers. So, i will take on a new integer value for each iteration of the loop. First i will be 0, then 1 on the next iteration, and so on.
You then ask if letter in i:. This can never be true. letter is a string, and i is an integer. A string can never be "in" an integer - so this if-statement will never execute. Rather, you want to check if letter is in the current word (the ith word in the list). The if-statement should read:
if letter in mylist[i]:
...
Where mylist[i] is the current word.
You then increment count and append i to a_list. You probably meant to append mylist[i] to a_list, but I don't see why you even need a_list. You just need count, since that keeps track of how many words you've encountered so far for which the condition is true. count is also the variable you should be returning in the end, since that is the purpose of the function: to return the number of words (not the words themselves) which contain a certain letter.
Also, the way your final print statement is indented makes it part of the function's body. It's after the return, though, which means it will never actually get a chance to print. When you use return inside a function, it ends the function, and flow of execution returns to the place from which the function was originally invoked.
One final change that needs to be applied, is that your function should accept a letter to look for as a parameter. Right now, your function only takes one parameter - the list of words through which to search.
Here are the changes I would apply to your code:
def count_letter(words, letter): # I find 'words' is a better name than 'mylist'.
count = 0
for i in range(len(words)):
current_word = words[i]
if letter in current_word:
count += 1
return count
Here is how you might use the function:
words = ["hello", "world", "apple", "sauce"]
letter = "e"
count = count_letter(words, letter)
print("The letter '{}' appeared in {} words.".format(letter, count))
Output:
The letter 'e' appeared in 3 words.
I think that 'takes' means that function must be defined with two parameters: words_list and letter:
def count_letter(words_list, letter):
Algorithm in natural language could be: give me sum of words where letter is present for every word in words list.
In Python it can be expressed as:
def count_letter(words_list, letter):
return sum(letter in word for word in words_list)
Some explanation: letter in word returns boolean value (True or False) and in Python bools are subclass of integer (True is 1 and False is 0). If letter is in word the result would be 1 and if not it would be 0. Summing up of results gives number of words where letter is present
I have read all your answers, some important points I wrote down, sat today again with my code, and after some more tries it worked...
So final version looks like:
words = ['fortran', 'basic', 'java', 'python', 'c++']
letter = "a"
def count_letter(words, letter):
count = 0
for word in words:
if letter in word:
count += 1
return count
print(count_letter((words),letter))
System response:
3
What is not yet obvious for me: correct indents (they were also part of a problem), and additional pair of parentheses around words in print line. But it comes with learning.
Thank you once again!
I am trying to write a function that takes a string as input and returns a string with all vowels repeated 4 times.
eg: apple becomes aaaappleeee
It works for every vowel, except for e, in which it repeats e an egregious amount of times.
Python 3. I have tried playing with the replace function, changing the replacement value to i+i+i+i, i*4, i(4), (i+i)*2, but nothing seems to help.
def exclamation(string):
for i in string:
if i in 'aeiou':
string = string.replace(i, i*4)
return string + '!'
exclamation('excellent') should return eeeexceeeelleeeent!
however, it returns:
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeexceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeelleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeent!
As stated, the function works fine for all other vowels, except e.
Thank you!
You shall never modify something you're iterating over, store the modified word in a new variable. Modifing your code it would be something like
def exclamation(string):
new = ''
for i in string:
if i in 'aeiou':
new += i*4
else:
new += i
return new + '!'
For every vowel you’re iterating through, the loop checks the condition, replaces the content in the same string and then iterates by 1 which now is the same string but instead of the next new letter, it now has to deal with 3 more of the same vowel. For example:
Let’s talk about the string ‘excellent’. For the first vowel ‘e’, it is replaced with ‘eeee’ resulting in the string being ‘eeeexcellent’, now when the second loop begins it starts at index(1) which is still an ‘e’ and this keeps going on. Never modify the iterable you’re iterating over.
It's not that e is being treated differently, but rather that you're replacing each e with eeee for as many es as there are in the word. If you try other words with multiples of the same vowel, you would see the same behavior there.
Instead of replacing for each vowel in the string, you should be doing each replacement once, which will effect every instance of that vowel in the string:
def exclamation(s):
for vowel in 'aeiou':
s = s.replace(vowel, vowel*4)
return s + '!'
print(exclamation('excellent'))
# 'eeeexceeeelleeeent!'
Note that this only works if the word is already lowercase (though that would be easy to fix, add capital vowels to the loop).
Another way of doing this would be to define a translation table to do all of the replacements at once:
trans = str.maketrans({vowel: vowel*4 for vowel in 'aeiou'})
def exclamation(s):
return s.translate(trans)
def exclamation(string):
result = ''
for i in string:
if i in 'aeiou':
vowel = i * 4
else:
vowel = i
result += vowel
return result + '!'
The reason why replace didnt work for excellent is because we have 3 'e' in which means for each of the 'e' in the loop, replace will multiply by 4 which will definitely give you 12 'e's per one 'e' in excellent
It is happening because your loop will consider the replaced 'e's as the element of the string as well.
Here is what I am saying:
String is excellent
Iterate through the string and check if the letter is vowel
If the letter is vowel, write that vowel 4 times.
By following the above steps, we will find this result as the first iteration.
First iteration will work on the first letter which is 'e' and will replace it with 'eeee'. So at the end of the first iteration, our final string will be: 'eeeexcellent'
Now for the second iteration, it will consider the final string we got after the first iteration. And for second iteration, the word to be consider will be 'e' only. So as you can see, you need to maintain the string as it is after each iteration, and save the replaced result to a new string. (it will always be a new string after all as string is not mutable)
def exclamation(string):
tmp = '' #taking temporary variable to store the current data
for i in string:
if i in 'aeiou':
tmp += i*4 # i*4 only if i is vowel
else:
tmp += i # keeping i as it is if it's not vowel
return tmp + '!'
You can also try list list comprehension which is easy to read and understand as well:
def exclamation(string):
newstr = [ i*4 if i in 'aeiou' else i for i in string]
return ''.join(newstr)+'!'
Define a function called count_engcons() which takes a string and
returns the number of consonants in the string (uppercase or
lowercase). For this problem, you may consider only letters in the
English language alphabet only. Also, for this problem "Y" is
considered a consonant (...not a vowel!). So for example
count_engcons("Tessellated?") should return 7, and
count_engcons("Aeiou!") should return 0. You must use a for loop, and
you are not allowed to use the .count() method on this problem.
I tried this:
def count_engcons(x):
vowels = ("aeiou")
count = 0
for count_engcons in text:
if not count_engcons in vowels:
count += 1
return x
However, it causes an error.
Thanks, jonrsharpe for the downvote.
You were checking if a character wasn't a vowel, so it would give bad results for characters such as ! or ?, you were also trying to access the string with different variable names (x and text), which makes no sense.
def count_engcons(text):
consonants = "bcdfghijklmnpqrstvwxyz"
count = 0
for c in text.lower():
if c in consonants:
count += 1
return count
So my function must take a list of strings and return the total number of capital letters that appear in positions other than the beginning of a word. Also to break this problem into a sub problem, it needs a second function that takes a single word and returns the number of capital letters that appear in positions other than the beginning of that word. So far I have a function that works, but I have been told it needs to be done better and I am not quite sure how to do that.
def count_strange_caps(words):
if words[0].isupper():
count = abs(1 -sum(1 for c in words if c.isupper())
elif words[0].islower():
count = abs(sum(1 for c in words if c.isupper()))
return count
def total_strange_caps(words):
total_count = 0
for word in words:
if word[0].isupper():
total_count -= 1
for letter in word:
if letter.isupper():
total_count += 1
return total_count
My teacher told me to combine the two list comprehensions in count_strange_caps as they are basically the same code and use the code from count_strange_caps in the inner for loop for the second function.
print(total_strange_caps(["Five","FiVe","fIVE"]))
print(total_strange_caps(["fIVE"]))
print(count_strange_caps("fIVE"))
These are the types of tests it needs to pass and if anyone could help me with a solution using more rudimentary concepts it would be much appreciated. I can not use numpy if that makes a difference.
You may use str.isupper() and sum() to achieve this. Using these, the function definition of count_strange_caps() should be like:
def count_strange_caps(word):
return sum(my_char.isupper() for my_char in word[1:]) # word[1:] to skip the first character
Sample run:
>>> count_strange_caps('HeLlo')
1
>>> count_strange_caps('HeLLo')
2
>>> count_strange_caps('heLLo')
2
Also, your total_strange_caps() can be simplified using sum() as:
def total_strange_caps(words):
return sum(count_strange_caps(word) for word in words)
Sampl run:
>>> total_strange_caps(['HeLlo', 'HeLLo', 'heLLo'])
5
You can use string comprehension as follows:
def total_strange_caps(words):
total_count = 0
for letter in words[1:]:
if letter.isupper():
total_count += 1
return total_count
print total_strange_caps("AbCdE")
Output:
2
I am trying to count the number of times 'e' appears in a word.
def has_no_e(word): #counts 'e's in a word
letters = len(word)
count = 0
while letters >= 0:
if word[letters-1] == 'e':
count = count + 1
letters = letters - 1
print count
It seems to work fine except when the word ends with an 'e'. It will count that 'e' twice. I have no idea why. Any help?
I know my code may be sloppy, I'm a beginner! I'm just trying to figure out the logic behind what's happening.
>>> word = 'eeeooooohoooooeee'
>>> word.count('e')
6
Why not this?
As others mention, you can implement the test with a simple word.count('e'). Unless you're doing this as a simple exercise, this is far better than trying to reinvent the wheel.
The problem with your code is that it counts the last character twice because you are testing index -1 at the end, which in Python returns the last character in the string. Fix it by changing while letters >= 0 to while letters > 0.
There are other ways you can tidy up your code (assuming this is an exercise in learning):
Python provides a nice way of iterating over a string using a for loop. This is far more concise and easier to read than using a while loop and maintaining your own counter variable. As you've already seen here, adding complexity results in bugs. Keep it simple.
Most languages provide a += operator, which for integers adds the amount to a variable. It's more concise than count = count + 1.
Use a parameter to define which character you're counting to make it more flexible. Define a default argument for using char='e' in the parameter list when you have an obvious default.
Choose a more appropriate name for the function. The name has_no_e() makes the reader think the code checks to see if the code has no e, but what it actually does is counts the occurrences of e.
Putting this all together we get:
def count_letter(word, char='e'):
count = 0
for c in word:
if c == char:
count += 1
return count
Some tests:
>>> count_letter('tee')
2
>>> count_letter('tee', 't')
1
>>> count_letter('tee', 'f')
0
>>> count_letter('wh' + 'e'*100)
100
Why not simply
def has_no_e(word):
return sum(1 for letter in word if letter=="e")
The problem is that the last value of 'letters' in your iteration is '0', and when this happens you look at:
word[letters-1]
meaning, you look at word[-1], which in python means "last letter of the word".
so you're actually counting correctly, and adding a "bonus" one if the last letter is 'e'.
It will count it twice when ending with an e because you decrement letters one time too many (because you loop while letters >= 0 and you should be looping while letters > 0). When letters reaches zero you check word[letters-1] == word[-1] which corresponds to the last character in the word.
Many of these suggested solutions will work fine.
Know that, in Python, list[-1] will return the last element of the list.
So, in your original code, when you were referencing word[letters-1] in a while loop constrained by letters >= 0, you would count the 'e' on the end of the word twice (once when letters was the length-1 and a second time when letters was 0).
For example, if my word was "Pete" your code trace would look like this (if you printed out word[letter] each loop.
e (for word[3])
t (for word[2])
e (for word[1])
P (for word[0])
e (for word[-1])
Hope this helps to clear things up and to reveal an interesting little quirk about Python.
#marcog makes some excellent points;
in the meantime, you can do simple debugging by inserting print statements -
def has_no_e(word):
letters = len(word)
count = 0
while letters >= 0:
ch = word[letters-1] # what is it looking at?
if ch == 'e':
count = count + 1
print('{0} <-'.format(ch))
else:
print('{0}'.format(ch))
letters = letters - 1
print count
then
has_no_e('tease')
returns
e <-
s
a
e <-
t
e <-
3
from which you can see that
you are going through the string in reverse order
it is correctly recognizing e's
you are 'wrapping around' to the end of the string - hence the extra e if your string ends in one
If what you really want is 'has_no_e' then the following may be more appropriate than counting 'e's and then later checking for zero,
def has_no_e(word):
return 'e' not in word
>>> has_no_e('Adrian')
True
>>> has_no_e('test')
False
>>> has_no_e('NYSE')
True
If you want to check there are no 'E's either,
def has_no_e(word):
return 'e' not in word.lower()
>>> has_no_e('NYSE')
False
You don't have to use a while-loop. Strings can be used for-loops in Python.
def has_no_e(word):
count = 0
for letter in word:
if letter == "e":
count += 1
print count
or something simpler:
def has_no_e(word):
return sum(1 for letter in word if letter=="e")