0

I have been trying these code but there is something wrong. I simply want to know if the first string is alphabetical.

def alp(s1):
    s2=sorted(s1)
    if s2 is s1:
        return True
    else:
        return False

This always prints False and when i say print s1 or s2, it says "NameError: name 's1' is not defined"

icecrime
  • 74,451
  • 13
  • 99
  • 111
billwild
  • 173
  • 1
  • 3
  • 12

5 Answers5

5

is is identity testing which compares the object IDs, == is the equality testing:

In [1]: s1 = "Hello World"
In [2]: s2 = "Hello World"

In [3]: s1 == s2
Out[3]: True

In [4]: s1 is s2
Out[4]: False

Also note that sorted returns a list, so change it to:

if ''.join(s2) == s1:

Or

if ''.join(sorted(s2)) == s1:
iabdalkader
  • 17,009
  • 4
  • 47
  • 74
4

I would do it using iter to nicely get the previous element:

def is_ordered(ss):
   ss_iterable = iter(ss)
   try:
       current_item = next(ss_iterable)
   except StopIteration:
       #replace next line to handle the empty string case as desired.
       #This is how *I* would do it, but others would prefer `return True`
       #as indicated in the comments :)
       #I suppose the question is "Is an empty sequence ordered or not?"
       raise ValueError("Undefined result.  Cannot accept empty iterable")

   for next_item in ss_iterable:
       if next_item < current_item:
           return False
       current_item = next_item
   return True

This answer has complexity O(n) in the absolute worst case as opposed to the answers which rely on sort which is O(nlogn).

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • @tvdien -- It does read a little strange. I'll happily accept proposals for better variable names :) – mgilson Nov 19 '12 at 15:56
  • I improved the readability and accounted for the case of an empty sequence. – Thijs van Dien Nov 19 '12 at 16:24
  • @tvdien -- I liked the edit, but I don't think that the case of an empty sequence should be accounted for since I don't think there is any reasonable default behavior to have. I suppose maybe raising a `ValueError` would be appropriate, but I didn't like having `pass` in there (effectively returning `None`) which would behave like `False` in a conditinal test where this is likely to be used ... – mgilson Nov 19 '12 at 16:27
  • If being ordered means that every second element is no lower than the first, an empty sequence is perfectly ordered. All other solutions also indicate this. BTW, try-except-else is Python idiom. – Thijs van Dien Nov 19 '12 at 16:30
  • @tvdien -- That definition of ordering doesn't work because there *is no first element*. OP can switch out my `raise` with `return True` if desired though and I think the func is still OK. Also, I know about `try-except-else-finally`, but there's no need for `else` here. We leave the block when we `raise ValueError` (or `return`). I don't like increasing my indentation level unnecessarily. Technically I could put the `return True` on an `else` on the `for` loop as well, but it doesn't make a difference and I think the code is easier to read without it. (but that's my opinion). – mgilson Nov 19 '12 at 16:36
  • @thg435 -- What do you mean `partial ordering`? This only checks whether OP's string is already ordered or not -- It doesn't actually do any ordering itself. – mgilson Nov 19 '12 at 18:35
  • @mgilson: yes, you're right. I was thinking your code only works for partially ordered sets, since it compares pairs of elements, but on a second thought it also requires the set to be totally ordered, due to transitivity. However, when a comparison is intransitive (as in `paper < scissors < rock` where `<` is `beats`), this method cannot be applied. – georg Nov 20 '12 at 08:30
  • @thg435 -- That's a fair point, although in that case the built in `sorted` would probably not be too happy either... – mgilson Nov 20 '12 at 19:39
4

You could see this answer and use something which works for any sequence:

all(s1[i] <= s1[i+1] for i in xrange(len(s1) - 1))

Example:

>>> def alp(s1):
...     return all(s1[i] <= s1[i+1] for i in xrange(len(s1) - 1))
...
>>> alp("test")
False
>>> alp("abcd")
True
Community
  • 1
  • 1
icecrime
  • 74,451
  • 13
  • 99
  • 111
  • This works since strings are indexible. It wouldn't work on arbitrary iterables however: `iter('foobar')`. That aside, I think this is a great answer -- Much better than sorting. +1 – mgilson Nov 19 '12 at 15:46
2

Make sure that you are comparing strings with strings:

In [8]: s = 'abcdef'

In [9]: s == ''.join(sorted(s))
Out[9]: True

In [10]: s2 = 'zxyw'

In [11]: s2 == ''.join(sorted(s2))
Out[11]: False

If s1 or s2 is a string, sorted will return a list, and you will then be comparing a string to a list. In order to do the comparison you want, using ''.join() will take the list and join all the elements together, essentially creating a string representing the sorted elements.

RocketDonkey
  • 36,383
  • 7
  • 80
  • 84
  • @billwild Because we are comparing `zxyw` and `wxyz`, and since `s2` is not alphabetical (i.e. equal to `wxyz`), we get False – RocketDonkey Nov 19 '12 at 15:42
2

use something like this:

sorted() returns a list and you're trying to compare a list to a string, so change that list to a string first:

In [21]: "abcd"=="".join(sorted("abcd"))
Out[21]: True

In [22]: "qwerty"=="".join(sorted("qwerty"))
Out[22]: False

#comparsion of list and a string is False
In [25]: "abcd"==sorted("abcd")
Out[25]: False
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504