Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a program that prints true if three words are entered in dictionary order

I am trying to create a program that asks the user for three words and prints 'True' if the words are entered in dictionary order. E.G:

Enter first word: chicken

Enter second word: fish

Enter third word: zebra

True

Here is my code so far:

first = (input('Enter first word: '))
second = (input('Enter second word: '))
third = (input('Enter third word: '))
s = ['a','b','c','d','e','f','g','h',
     'i','j','k','l','m','n','o','p',
     'q','r','s','t','u','v','w','x',
     'y','z','A','B','C','D','E','F',
     'G','H','I','J','K','L','M','N',
     'O','P','Q','R','S','T','U','V',
     'W','Z','Y','Z']
if s.find(first[0]) > s.find(second[0]) and s.find(second[0]) >                                  s.find(third[0]):
    print(True)
like image 887
Joe Dingle Avatar asked Oct 17 '15 06:10

Joe Dingle


3 Answers

If you work on a list of arbitrary length, I believe using sorted() as other answers indicate is good for small lists (with small strings) , when it comes to larger lists and larger strings and cases (and cases where the list can be randomly ordered), a faster way would be to use all() built-in function and a generator expression (This should be faster than the sorted() approach). Example -

#Assuming list is called lst
print(all(lst[i].lower() < lst[i+1].lower() for i in range(len(lst)-1)))

Please note, above would end up calling str.lower() on every string (except for first and last) twice. Unless your strings are very large, this should be fine.

If your strings are really very large compared to the length of the list, you can create another temporary list before doing the all() that stores all the strings in lowercase. And then run same logic on that list.

You can create your list (by taking inputs from the user) using a list comprehension, Example -

lst = [input("Enter word {}:".format(i)) for i in range(3)] #Change 3 to the number of elements you want to take input from user.

Timing results of the above method vs sorted() (modified code of sorted() to work case-insensitively) -

In [5]: lst = ['{:0>7}'.format(i) for i in range(1000000)]

In [6]: lst == sorted(lst,key=str.lower)
Out[6]: True

In [7]: %timeit lst == sorted(lst,key=str.lower)
1 loops, best of 3: 204 ms per loop

In [8]: %timeit all(lst[i].lower() < lst[i+1].lower() for i in range(len(lst)-1))
1 loops, best of 3: 439 ms per loop

In [11]: lst = ['{:0>7}'.format(random.randint(1,10000)) for i in range(1000000)]

In [12]: %timeit lst == sorted(lst,key=str.lower)
1 loops, best of 3: 1.08 s per loop

In [13]: %timeit all(lst[i].lower() < lst[i+1].lower() for i in range(len(lst)-1))
The slowest run took 6.20 times longer than the fastest. This could mean that an intermediate result is being cached
100000 loops, best of 3: 2.89 µs per loop

Result -

For cases that should return True (that is already sorted lists) the using sorted() is quite faster than all() , since sorted() works well for mostly-sorted lists.

For cases that are random, all() works better than sorted() because of the short-circuiting nature of the all() (it would short-circuit when it sees the first False ).

Also, there is the fact that sorted() would create a temporary (sorted list) in memory (for comparison), whereas all() would not require that (and this fact does attribute to the timings we see above).


Earlier answer that directly (and only applies to this question) you can simply directly compare the strings as such, you do not need another string/list for alphabets. Example -

first = (input('Enter first word: '))
second = (input('Enter second word: '))
third = (input('Enter third word: '))
if first <= second <= third:
    print(True)

Or if you want to compare only the first characters (though I highly doubt that) -

if first[0] <= second[0] <= third[0]:
    print(True)

To compare the strings case-insensitively, you can convert all the string to lowercase, before comparison. Example -

if first.lower() <= second.lower() <= third.lower():
    print(True)

Or the simpler -

print(first.lower() <= second.lower() <= third.lower())
like image 165
Anand S Kumar Avatar answered Nov 10 '22 05:11

Anand S Kumar


Yes, lists do not have the find method. Though you don't even have to use lists. The <= (as well as >=) operator compare sequences lexicographically. In addition, Python supports chained comparisons. Here's how I'd write it:

first = input('Enter first word: ')
second = input('Enter second word: ')
third = input('Enter third word: ')
print(first <= second <= third)

If there're more than 3 words, you'd gather them into a list, sort it and compare it against the source list. Example:

words = input('Enter words (separated by whitespace): ').split()
print(sorted(words) == words) # True if sorted() didn't re-order anything

Both of these approaches will work reasonably well for small number of words. If the number of words is big, you should consider using a short-circuiting solution using the built-in all function and a generator expression:

prev_it, cur_it = iter(words), iter(words)
# Consume first element
next(cur_it)
# Pairwise iteration
print(all(prev <= cur for prev, cur in zip(prev_it, cur_it)))

which is an efficient generalization of the first solution.


If you want to perform case-insensitive comparison, use str.lower (or str.casefold, in Python 3.3+).

Example for the first code snippet:

print(first.lower() <= second.lower() <= third.lower())

Example for the list-based approaches:

words = [s.lower() for s in input('Enter words (separated by whitespace): ').split()]
like image 6
vaultah Avatar answered Nov 10 '22 05:11

vaultah


Store the words in a list and then check it with sorted(). You can make it ignore case by specifying a key that looks at the lowercase version of each word for comparison:

words = input("Enter three words, separated by spaces: ").split()
print(words == sorted(words, key=str.lower))
like image 3
TigerhawkT3 Avatar answered Nov 10 '22 05:11

TigerhawkT3