-1

The function takes a filename and x (which is meant to return the first 2 or 4 vowels in filename). The code I have written returns vowels but I'm not exactly sure what it is returning. The code should pass a doctest. I'm still trying to figure it out but if anyone has any advice on what I am doing wrong it would be very much appreciated as I am still relatively new to python.

the contents of the filename is: ("I have a bunch of red roses")

def return_vowels(filename, x):
    """
    >>> return_vowels("roses.txt", 2)
    'Ia' #returns the first two vowels in the text
    >>> return_vowels("roses.txt", 3)
    'Iae'#returns the first three vowels in the text
    """
    files = open(filename)
    text_file = files.read()
    consonants = "BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz"#do not want consonants
    s_with_vowels = ""
    index = 0
    while index < x:
        for letter in read_files:
            if letter not in consonants:
                s_with_vowels += letter
        return s_with_vowels

if __name__=="__main__":
    import doctest
    doctest.testmod(verbose=True)
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • What should be returned when `x` is 4? Should it be `Iaea` or `Iaeu`? – inspectorG4dget May 23 '15 at 06:09
  • Some advice, flip your check & check for 'aeiou' (don't forget case). As its stands, if your file is called "I have 2 bunches of red roses", your code will consider 2 to be a vowel. – Mawg says reinstate Monica May 23 '15 at 06:10
  • it should return 'Iaea' if x is 4 – python_learner May 23 '15 at 06:10
  • Do you use an IDE? PyCHarm community edition is excellent https://www.jetbrains.com/pycharm-educational/download/ it has a debugger and will let you step through your code to see what is happening. Get into the habit of doing that & you will need to ask her much less, if at all. – Mawg says reinstate Monica May 23 '15 at 06:11
  • I would recommend upgrading to 3.x unless you have compelling reasons not to do so. It is not completely backward compatible, so best start coding the Python of the future, not the past. I cannot stress the debugger strongly enough; it is probably your single greatest tool. You can set a `breakpoint` on a line of code, run to that line & then see the value of your variables at that point (plus much more) – Mawg says reinstate Monica May 23 '15 at 06:27
  • we use python 2.7 for my uni course, they didn't want to upgrade because they experienced problems with up to date python installations. – python_learner May 23 '15 at 08:53

3 Answers3

0

First of all you don't need to define a nested while and for loop, You only need to iterate over the line and at each word check if it is a consonant or a vowel ?

If it comes out to be a vowel then you simply increase the count and at the end of iteration you check of the count hasn't exceeded the passed value x.

Other thing to keep in mind was you were checking the word with consonants, which missed many characters such as number, special characters , spaces ,etc. SO all of these would had been counted as vowels. So it is better to check against the string of Vowels to overcome this drawback.

def count_vovels(filename, x):
    """
    >>> return_vowels("roses.txt", 2)
    'Ia' #returns the first two vowels in the text
    >>> return_vowels("roses.txt", 3)
    'Iae'#returns the first three vowels in the text
    """
    files = open(filename, "r")
    text_file = files.read()
    #consonants = "BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz"#do not want consonants
    vowels = "aeiou"
    s_with_vowels = ""
    index = 0
    #while index < x:
    for letter in text_file:
        if letter.lower() in vowels:
            s_with_vowels += letter
            index+=1
        if index >=x:
            break
    files.close()
    return s_with_vowels

print count_vovels("sample.txt", 2)
>>> Ia
print count_vovels("sample.txt", 3)
>>> Iae
print count_vovels("sample.txt", 4)
>>> Iaea
ZdaR
  • 22,343
  • 7
  • 66
  • 87
0

I modified your code, as per my comments above. I also made some other changes, all of which are marked by comments beginning with ####

#### x??  Will you remember what X means when you come back to the code in 6b months time?
#### def return_vowels(filename, x):
def return_vowels(filename, numberOfVowelsToFind):

    #### I had problems with your comments in the doctest expected output (doctest expected them)
    """
    >>> return_vowels("roses.txt", 2)
    'Ia'

    >>> return_vowels("roses.txt", 3)
    'Iae'
    """

    #### slightly better name
    textFile = open(filename)
    fileBody = textFile.read()

    #### make your check inclusory, not exclusory.
    #### what if your file contained "I have a bunch of red roses"? 2 would be seen as a vowel
    #### consonants = "BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz"#do not want consonants
    vowels = 'AEIOU'

    #### use a slightly more meaningful variable name
    #### s_with_vowels = ""
    firstVowelsFound = ""

    index = 0
    while index < numberOfVowelsToFind:
        for letter in fileBody:
            if letter.upper() in vowels:
                firstVowelsFound += letter

            #### You need this check to know when you are done
            if len(firstVowelsFound) == numberOfVowelsToFind:
                return firstVowelsFound

if __name__=="__main__":
    import doctest
    doctest.testmod(verbose=True)

Gratz on using doctest, btw. Here's the output of the above code:

E:\coding\Python\Python\python.exe
C:/Users/me/PycharmProjects/untitled/vowels roses.txt Trying:
return_vowels("roses.txt", 2) Expecting:
'Ia' ok Trying:
return_vowels("roses.txt", 3) Expecting:
'Iae' ok 1 items had no tests:
main 1 items passed all tests: 2 tests in main.return_vowels 2 tests in 2 items. 2 passed and 0 failed. Test passed.

Process finished with exit code 0

Mawg says reinstate Monica
  • 38,334
  • 103
  • 306
  • 551
0

This works as expected:

def find_vowels(file_name, limit):
    """
    >>> # returns the first two vowels in the text
    >>> find_vowels("roses.txt", 2)
    'Ia'
    >>> # returns the first two vowels in the text
    >>> find_vowels("roses.txt", 3)
    'Iae'
    """
    count = 0
    res = []
    vowels = set('aeiuoAEIOU')
    with open(file_name) as fobj:
        for line in fobj:
            for c in line:
                if c in vowels:
                    count += 1
                    res.append(c)
                if count >= limit:
                    break
    return ''.join(res)

if __name__=="__main__":
    import doctest
    doctest.testmod(verbose=True)

and passes the tests:

Trying:
    find_vowels("roses.txt", 2)
Expecting:
    'Ia'
ok
Trying:
    find_vowels("roses.txt", 3)
Expecting:
    'Iae'
ok
1 items had no tests:
    __main__
1 items passed all tests:
   2 tests in __main__.find_vowels
2 tests in 2 items.
2 passed and 0 failed.
Test passed.    

A few things.

  1. I use a set with vowels vowels = set('aeiuoAEIOU')
    Checking for membership in sets is faster than in lists.

  2. I use a list to hold the found vowels res = []. While adding to string s += works, it is considered an anti pattern due to potentially long run times especially with other implementations such as PyPy. This does not matter at all for your example. But writing good code won't hurt.

  3. I use the with statement to open the file. Python will close it for me as soon as I dedent back to the level of `with``` ''.join(res).

  4. I use a for loop to go over all lines of the file. Using on line at a time makes it possible to work with really large files efficiently.

  5. I don't use while to check for the limit of vowels but rather a counter and a for loop with explicit incrementing. The for loop terminates when the end of the file is reached. A while might go on forever if the limit is not found yet.

  6. This ''.join(res) creates a string from my result list.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
  • Thank you very much for the explanation, it really helped me understand the many things i was doing wrong. I have not yet learned about sets but if i was to use a list although it would take longer, will the output still be the same? – python_learner May 23 '15 at 08:00
  • Yes. For your small example you can as well use a list. The `in` test does the same. Sets are really useful if (a) the set you search in is large (not the case here) and (b) you do the search very often (also not really the case here). I still like to use a set just to make my code a **little bit** more future proof. If the file gets much larger your program should still work in a reasonable time. – Mike Müller May 23 '15 at 08:10