1

say I have something like:

array = ['apple', 'banana', 'carrot', 'dragonfruit', 'eggplant']

Now I want to print the values in this array, where the value doesn't start with a vowel.

ie

banana
carrot
dragonfruit 

I could do it:

for str in array:
    if str[0].lower() not in ('a','e','i','o','u'):
        print str

What I'm wondering, is if there is a pythonic of way of saying something like:

for str in array where str[0].lower() not in ('a','e','i','o','u'):
dwjohnston
  • 11,163
  • 32
  • 99
  • 194
  • 2
    List comprehensions are great, but there is nothing *unpythonic* about having to have a separate `for` loop and `if` condition. **I would say your original solution is better**, as it is clearer, simpler and more readable - but thats what makes this a very subjective question. –  Jul 10 '14 at 04:43

4 Answers4

5

Do you know that str.startswith accepts a tuple of prefixes?

Implementation

for fruit in (elem for elem in array 
              if not elem.startswith(('a','e','i','o','u'))):
    print fruit

Output

banana
carrot
dragonfruit
Abhijit
  • 62,056
  • 18
  • 131
  • 204
4
for str_ in (s for s in array if s[0].lower() not in 'aeiou'):
    print(str_)

Don't use str as it shadows the built-in string constructor.

That said this looks more like a regex than a list comp to me.

import re

words = ['apple', 'banana', 'carrot', 'dragonfruit', 'eggplant']
pat = re.compile(r'''
        \b            # Begin a word
        [^aeiou\s]\w* # Any word that doesn't begin with a vowel (or a space)
        \b            # End a word''', re.X)
matches = re.findall(pat, ' '.join(words), re.I)
print(matches)

Nevermind, I can't get this to work and don't have time to muck with it at the moment. I fail at regex :(

This bothered me too much to leave wrong. I fixed it.

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • +1 for generator; ±0 for `str_` instead of something more descriptive as `fruit` given the starting array (which should probably be called `fruits`) Yes, I have a naming fetish but am not ashamed. – msw Jul 10 '14 at 02:56
  • 1
    @msw agreed, but I used `str_` illustratively to highlight why NOT to use `str` and how to avoid shadowing built-ins if you want to (sometimes you really DO want to call something `class`, so you call it `class_` instead, e.g. in `BeautifulSoup`) – Adam Smith Jul 10 '14 at 02:57
2

startswith(('a','e','i','o','u')basestring.join() and list comprehension are always your good friends to be Pythonic:)

You can use either this:

no_vowels = [str for str in array if not str.startswith(('a','e','i','o','u'))]
for nv in no_vowels:
  print nv

or this:

print '\n'.join([str for str in array if not str.startswith('a','e','i','o','u'))] 
shihpeng
  • 5,283
  • 6
  • 37
  • 63
  • to be honest, the "pythonic" way is `for fruit in words: if not fruit.startswith(('a','e','i','o','u')): print(fruit)` not stringing together a huge list comp with a string join, but OP specifically didn't want that. – Adam Smith Jul 10 '14 at 03:16
2

You can use list comprehension which reads similarly to what you suggested in your question.

Note the 'str for str' at the start and the 'if' instead of 'where'.

Note also that strings are iterable so you can simplify your if statement to: if x[0].lower() not in 'aeiou'

So an easy solution could be:

all_fruit = ['apple', 'banana', 'carrot', 'dragonfruit', 'eggplant']

#filter out fruit that start with a vowel
consonant_fruit = [fruit for fruit in all_fruit if fruit[0].lower() not in 'aeiou']

for tasty_fruit in consonant_fruit:
    print tasty_fruit

Alternatively you could use a generator expression which is more memory efficient, the only change in this example is '[ ]' to '( )'

all_fruit = ['apple', 'banana', 'carrot', 'dragonfruit', 'eggplant']

#filter out fruit that start with a vowel
consonant_fruit = (fruit for fruit in all_fruit if fruit[0].lower() not in 'aeiou')

for tasty_fruit in consonant_fruit:
    print tasty_fruit

There is also the filter builtin:

all_fruit = ['apple', 'banana', 'carrot', 'dragonfruit', 'eggplant']

for tasty_fruit in filter(lambda fruit: fruit[0].lower() not in 'aeiou', all_fruit):
    print tasty_fruit
Jeremy Allen
  • 6,434
  • 2
  • 26
  • 31