Reputation: 33
Our goal is to search through a user input string and count how many vowels are found inside of it. Unfortunately I am stuck here, any help?
def numVowels(s):
vowels= "AEIOUaeiou"
if s == '':
return 0
else:
totalVowels = list(filter(lambda vowels:sum("AEIOUaeiou"), s))
print(len((totalVowels)))
Upvotes: 3
Views: 2660
Reputation: 61509
I will show three approaches in pairs, each time doing it via lambda
and then via the equivalent generator expression. It's important to understand that generator expressions (and list comprehensions) are simply syntactic sugar for a pair of map
and filter
operations, and can be translated back and forth mechanically. However, the expression/comprehension way is generally considered more Pythonic.
The key to a problem like this is that you have to figure out what you want to do in the filter and what you want to do in the map. That is: you have to be able to write code that looks at one element and decides whether or not to include it; as well as code that looks at one element and transforms it into a more usable value.
So before we show the code, let's make sure that we can:
given a letter, determine whether it is contained within our vowels
string. That is trivial: we can literally ask Python whether letter in vowels
(assuming letter
is some variable - but beware that with vowels
being a string, this does a substring search; you should convert vowels
to a set
first). To make a lambda
out of that, we simply write: lambda letter: letter in vowels
. (We can use whatever variable names we like here: it's the same as writing a function.)
given a letter, translate it into a 1
if it is a vowel, and a 0
otherwise. Actually, using the letter in vowels
result will work just as well, because that returns True
or False
, and those are usable as numeric values 1
and 0
respectively. Depending on how you interpret the Python axiom explicit is better than implicit
, you might instead prefer to write int(letter in vowels)
, or even 1 if letter in vowels else 0
. To cut down on the number of examples, I will just use letter in vowels
, even though in my own code I'm fond of that last one :)
Also, let's simplify. As I noted earlier, our vowels
should be a set
. I will show that only once, here: vowels = set("AEIOUaeiou")
. The functions shown below, naturally, assume that's a global ;) Finally, note that there is no reason to treat an empty string differently. You can perfectly well iterate over an empty string, find no elements, sum them to 0, find its length to be 0, etc. It does not change the logic at all. Special cases aren't special enough
.
Onward to full code.
We can do what you wanted to do, which is: include elements that are vowels, and perform no transformation - determine the result by the length of the resulting vowel list.
def vowels_by_filter(string):
return len(filter(lambda letter: letter in vowels, string))
def vowels_by_filter_expression(string):
return len(letter for letter in string if letter in vowels)
Or we can transform all the letters to 1
or 0
(i.e., the "number of vowels" that each letter contains), and add up the results:
def vowels_by_map(string):
return sum(map(lambda letter: letter in vowels, string))
def vowels_by_map_expression(string):
return sum(letter in vowels for letter in string)
Or we can combine those approaches - include only the elements that are vowels, and then transform them to 1 (since everything we include is a vowel, it must transform to 1, and we don't need to check the value again):
def vowels_by_both(string):
return sum(map(lambda letter: 1, filter(lambda letter: letter in vowels, string)))
def vowels_by_full_expression(string):
return sum(1 for letter in string if letter in vowels)
The equivalence in each pair should be fairly obvious. With a generator expression (or list comprehension), the part before for
is our map
, and the part at the end after if
(if included) is our filter
. We always have to write a "map" with these (even if the transformation is the equivalent of lambda x: x
), but it saves us from having to write out the full lambda
syntax, and we use the same free variable for both the "map" and the "filter", when present (i.e., our iteration variable, the letter
in for letter in string
).
Upvotes: 3
Reputation: 180401
Using your own code you need to filter characters not in vowels, you can lower each character and make vowels a set for O(1) lookups:
def numVowels(s):
vowels = {"a","e","i","o","u"}
if s == '':
return 0
else:
totalVowels = list(filter(lambda x: x.lower() in vowels , s))
return len(totalVowels)
Which can simply become:
def numVowels(s):
vowels = {"a","e","i","o","u"}
return len(list(filter(lambda x: x.lower() in vowels , s)))
Each x
in the lambda is each character from s
, passing lambda x: x.lower() in vowels
to filter will filter any character from s
that is not in our vowels set so we are left with a list of just non-vowles.
You can combine sum
with your filter
and lambda
:
def numVowels(s):
vowels= {"a","e","i","o","u"}
return sum(1 for _ in filter(lambda x: x.lower() in vowels , s))
Or generally when a lambda was not a nesessity, simply returning the generator expression would be the best approach:
def numVowels(s):
vowels= {"a","e","i","o","u"}
return sum(x.lower() in vowels for x in s))
The last part of the answer is the most efficient for large input as sets are O(1)
for lookups. x.lower() in vowels
will either be True/False
1
or 0
so you just need to sum them all. If s
is an empty string or there are no vowels sum
will return 0
An example of how x.lower() in vowels
works:
In [8]: tests = "String with vowels"
In [9]: l = [x.lower() in vowels for x in tests]
In [10]: l
Out[10]: # list of booleans
[False,
False,
False,
True,
False,
False,
False,
False,
True,
False,
False,
False,
False,
True,
False,
True,
False,
False]
In [11]: l = [int(b) for b in l]
In [12]: l # list of 1's and 0's equating to True and False
Out[12]: [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0]
Upvotes: 3
Reputation: 397
There are a lot of answers and here and my answer is not optimal, but I will post it just as "yet another option".
You can use reduce
method. But this method is not recommended to use and in Pyton 3 it's been hidden in functools
module from built-in.
from functools import reduce # in Python 3
def numVowels(str):
return reduce(lambda acc, ch: x+1 if ch in 'AEIOUaeiou' else acc, str, 0)
print numVowels('abc')
Upvotes: -1
Reputation: 30258
There are many ways to solve the problem of counting the number of vowels in a word, but just looking at fixing your code:
totalVowels = list(filter(lambda c: c in vowels, s))
print(len(totalVowels))
Will now show the number of vowels.
It looks like you didn't really understand how filter()
works, suggest rereading the documentation.
Upvotes: 0
Reputation: 6641
Your code is far off.
As @acushner said summing a string makes no sense, as Python starts with 0 as a default and breaks as you cannot sum an integer and a string. (Luckily, strong typing like this allows us to fix errors while developing)
Also let us suppose the the lambda function worked, sum
would return an integer, the same each time, and you would be filtering on that. The output may be either the full string or nothing.
Upvotes: 0
Reputation: 113978
vowels = "aeiou"
count_vowels = lambda s: 0 if not s else ((s[0].lower() in vowels) + count_vowels(s[1:]))
>>> count_vowels("hello world")
3
maybe?
Upvotes: 3
Reputation: 90889
You can simply use a generator expression and provide it to sum()
to get the number of vowels, Example -
>>> def numVowels(s):
... vowels= "AEIOUaeiou"
... return sum(1 for x in s if x in vowels)
...
>>> numVowels("abcdefa")
3
>>> numVowels("")
0
>>> numVowels("bcdfgh")
0
Upvotes: 3