4

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.

Johnny
  • 233
  • 3
  • 4
  • 6
  • When letters == 0 what will happen? Why are you testing for `while letters >= 0`? Can you explain **why** you're doing this? An explanation would be helpful. – S.Lott Dec 30 '10 at 14:58

9 Answers9

14
>>> word = 'eeeooooohoooooeee'
>>> word.count('e')
6

Why not this?

user225312
  • 126,773
  • 69
  • 172
  • 181
12

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
moinudin
  • 134,091
  • 45
  • 190
  • 216
1

Why not simply

def has_no_e(word):
    return sum(1 for letter in word if letter=="e")
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
1

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")
Slater Victoroff
  • 21,376
  • 21
  • 85
  • 144
Nope
  • 34,682
  • 42
  • 94
  • 119
1

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

Yonatan
  • 1,187
  • 15
  • 33
1

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.

Klaus Byskov Pedersen
  • 117,245
  • 29
  • 183
  • 222
1

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.

sjberry
  • 11
  • 1
1

@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

  1. you are going through the string in reverse order
  2. it is correctly recognizing e's
  3. you are 'wrapping around' to the end of the string - hence the extra e if your string ends in one
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
1

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
aid
  • 136
  • 3