h-man
h-man

Reputation: 83

Counting abecedarian words in a list: Python

Working on a very common problem to identify whether word is abecedarian (all letters in alphabetical order). I can do one word in several ways as discovered in "Think Python"; but, would like to be able to iterate through a list of words determining which are abecedarian and counting those that are.

def start():
    lines= []
    words= []
    for line in open('word_test1.txt'):
        lines.append(line.strip())
    numlines=len(lines)
    count = 0

    for word in lines[:]:
        i = 0
        while i < len(word)-1:
            if word[i+1] < word[i]:
                return 
            i = i+1
        print (word)
    count= count + 1
    print (count)
start()

I think my problem lies with the "return" in the "while i" loop. In the list I'm using there are at least three abecedarian words. The above code reads the first two (which are the first entries), prints them, counts them but on the following non-abecedarian word breaks out of the loop and ends the program.

I'm new at programming and this has taken me several hours over a couple of days.

Upvotes: 4

Views: 2537

Answers (6)

Michel
Michel

Reputation: 15

I have this solution for you - I have found it in the same place as you. I hope it still helps.

def is_abecedarian(word):
    word.lower()
    letter_value=0
    for letter in word:
        if ord(letter) < letter_value:
            return False
        else:
            letter_value = ord(letter)
    return True

fin = open('words.txt')
words_no = 0
for line in fin:
    word = line.strip()
    if is_abecedarian(word):
        words_no = words_no + 1

print words_no

Upvotes: 0

pillmuncher
pillmuncher

Reputation: 10162

I like iterools:

from itertools import tee, izip

def pairwise(iterable):
    a, b = tee(iterable)
    next(b)
    return izip(a, b)

def is_abcdarien(word):
    return all(c < d for c, d in pairwise(word))

words = 'asdf', 'qwer', 'fghi', 'klmn', 'aabcd', 'abcd'

print filter(is_abcdarien, words)
print len(filter(is_abcdarien, words))

Result:

('fghi', 'klmn', 'abcd')
3

Change c < d to c <= d if you want non-strict ordering, so that "aabcd" is also abcdarian, .

Upvotes: 0

Hugh Bothwell
Hugh Bothwell

Reputation: 56654

A slightly reorganized approach:

def is_abcedarian(word):
    return sorted(s)==list(s)

def main():
    # read input file
    with open('word_test1.txt') as inf:
        words = [line.strip() for line in inf]

    # figure out which words are "good"    
    good_words = [word for word in words if is_abcedarian(word)]

    # print the "good" words
    print("\n".join(good_words))
    print(len(good_words))

if __name__=="__main__":
    main()

Upvotes: 0

Raymond Hettinger
Raymond Hettinger

Reputation: 226376

No need for low level programming on this one :-)

def is_abcedarian(s):
    'Determine whether the characters are in alphabetical order'
    return list(s) == sorted(s)

The use filter to run over a list of words:

>>> filter(is_abcedarian, ['apple', 'bee', 'amp', 'sun'])
['bee', 'amp']

Upvotes: 11

Abhijit
Abhijit

Reputation: 63737

I believe you intended to break from the while loop when you find the letter's are not in order and instead you issued the return statement, which returns you from the function start. There could be couple of ways to do this

You can use Exception, to raise a StopIteration Exception and catch it outside the while loop.

for word in lines[:]:
    try:
        i = 0
        while i < len(word)-1:
            if word[i+1] < word[i]:
                raise StopIteration 
            i = i+1
        print (word)
    except StopIteration:
        None

You can also try setting a flag found and then use it later to test for printing the word

Upvotes: 1

Greg Hewgill
Greg Hewgill

Reputation: 993343

The return statement is breaking out of the entire start() function. There are many possible ways to solve this, but the clearest might be to break your code into two functions like this:

def is_abcedarian(word):
    i = 0
    while i < len(word)-1:
        if word[i+1] < word[i]:
            return False
        i = i+1
    return True

def start():
    lines= []
    words= []
    for line in open('word_test1.txt'):
        lines.append(line.strip())
    numlines=len(lines)
    count = 0

    for word in lines[:]:
        if is_abcedearian(word):
            print (word)
    count= count + 1
    print (count)

In this example, the return statements in is_abcedarian() returns only from that function, and the return value is then tested by the if statement inside the for loop.

Once you have split apart your program in this way, you have the added benefit of being able to use your is_abcedarian() function from other places (in future related code you might write).

Upvotes: 3

Related Questions