3

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)))
3
  • 2
    test what lambda vowels:sum("AEIOUaeiou") does Commented Sep 14, 2015 at 19:54
  • your code doesnt really do much from what I can tell Commented Sep 14, 2015 at 19:54
  • Stuck how? You are trying to sum() the vowels, which makes no sense. Commented Sep 14, 2015 at 19:55

7 Answers 7

3

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).

Sign up to request clarification or add additional context in comments.

Comments

3

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

4 Comments

it sounds like the goal of this excersize is to practice lambdas :P but yes this is how you should accomplish the task without the requirement of lambdas
Guessing this answer got downvoted because it does not help the OP much with his homework.
maybe ... I certainly did not downvote it as this is the "right" way to do it ... or at least a way (I woulda done sum(x in vowels for x in s) ... but yeah :P
Translating a generator expression (or list comprehension) to a pair of map and filter operations is a mechanical process. Although for that purpose, it would be simpler to write the code so that it sums 0s for non-vowels instead of skipping them entirely, and then translate that to a map, no filter required. Alternately, filter and count the vowels, per OP's original approach.
3
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?

Comments

3

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]

4 Comments

Using filter like this hurts... Also the if...else logic is useless... len will return 0 on empty string. Also (( ... ))
@JBernardo, I used the OP's own code showing them how to do it with their code, I have also provided better more efficient ways than any other answer to do it.
For completeness, could you also show the approaches where the list is not filtered, but vowels are translated to 1 and non-vowels are translated to 0? This is otherwise an excellent answer.
@KarlKnechtel, I added an example, if you have a better approach feel free to edit
0

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.

Comments

0

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.

Comments

-1

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')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.