LaffyTaffyKidd
LaffyTaffyKidd

Reputation: 47

Python: Indexing a string with specific conditions

I need help with this: Find the number of words that contain none of the five vowels and three y's.

So far, I have:

def no_vowels_yyy(s):
        count = 0
        list_of_vowels = ['a', 'e', 'i', 'o', 'u']
        for i in range(0, len(s)):
                if s[i] not in list_of_vowels and (s[i] == 'y') == 3:
                        return True
        return False

This is not working though...

Upvotes: 0

Views: 111

Answers (5)

steveha
steveha

Reputation: 76715

Here is a slightly different solution.

First, we build a set of vowels. It is very fast to check if a particular character is in this set, or not; faster than checking in a list. Also, we build it once, outside the function, instead of building it every time the function is called.

We use any() with a generator expression that checks each character to see if it is in the set. If any character is in the set of vowels, we return False.

Next, we use sum() with a generator expression to count how many 'y' characters there are; for each character that is a 'y', the value 1 is added by the sum() function. We return whether this result is 3.

This will be a bit faster than looping over the string with an index and updating a counter variable. This is more of a "Pythonic" solution. On the other hand, this loops over the string twice rather than once.

_vowels = set(['a', 'e', 'i', 'o', 'u'])

def no_vowels_yyy(s):
    if any(ch in _vowels for ch in s):
        return False

    return s.count('y') == 3

print(no_vowels_yyy("zyzyxy"))

Upvotes: 1

AndrewR
AndrewR

Reputation: 6748

Your check for the number of y's (s[i] == 'y') == 3: is what's causing it not to work. Comparing s[i] to 'y' will give you a boolean (true/false) result, not the number of matches. Since you are looping through, you could just keep a count of the number of y's you've found.

def no_vowels_yyy(s):
    count = 0
    list_of_vowels = ['a', 'e', 'i', 'o', 'u']
    for i in range(0, len(s)):
            if s[i] in list_of_vowels:
                return False
            if s[i] == 'y':
                count += 1

    return count == 3

Upvotes: 2

jfs
jfs

Reputation: 414335

def no_vowels_yyy(s, _vowels=set("aeiou")):
    return s.count("y") == 3 and _vowels.isdisjoint(s)
print(no_vowels_yyy("zyzyxy")) # -> True

Or a more readable version:

def no_vowels_yyy(s):
    return s.count("y") == 3 and all(c not in "aeiou" for c in s)

Upvotes: 1

user2032433
user2032433

Reputation:

Since others have already told you what's the problem, I'll just offer a solution of my own. This is probably the best way, I can't see why not to use string.count()-method:

def no_vowels_yyy(s):
    if any(c in {'a', 'e', 'i', 'o', 'u'} for c in s):
        return False
    return s.count('y') == 3

Upvotes: 2

Jon Clements
Jon Clements

Reputation: 142176

Just to show another way...:

from collections import Counter
def func(text):
    freq = Counter(text)
    return freq['y'] == 3 and not (freq.viewkeys() & 'aeiou')

Has the advantage of just one parse, but doesn't short circuit on vowels...

Otherwise, to short circuit as soon as possible:

y_count = 0
for ch in word:
    if ch in {'a', 'e', 'i', 'o', 'u'}:
        return False
    elif ch == 'Y':
        y_count += 1
        if y_count > 3:
            return False
return y_count == 3

Upvotes: 1

Related Questions