I want to understand Python's behavior for tuple comparison operators, specifically < (the less-than operator).
edit: Now I get it, thank you Jaroslaw for a clear answer.
My error was thinking 1) "Lexicographical comparison" was a synonym for "string compare", and 2) thinking that the "string compare logic" applied to each element of the tuples being compared instead of at the tuple-level. Which yields valid behavior for == but not so much for <.
On the off chance anyone else gets stuck on the distinction.
excerpt from wikipedia (emphasis added)4: ...lexicographical order ... is a generalization of the way the alphabetical order of words is based on the alphabetical order of their component letters. This generalization consists primarily in defining a total order over the sequences ... of elements of a finite totally ordered set, often called alphabet.
original question text follows...
Wait, you say, hasn't this been asked before? Yes... and pretty well answered for == (equality). I want to understand why ( 1, 2 ) < ( 1, 3 ) yields True (note the < less than operator, code example below). This is likely just a python-newbie error on my part, but I am having trouble finding it.
I've read some other questions about how tuple comparisons involves "lexicographic comparisons of the respective elements form each tuple."
Question: python-tuple-comparison-odd-behavior: This question is about using the in operator, I'm interested in < (less than), not so much the behavior of in (at least not yet).
Question: python-tuple-comparison: For this one the answer says (emphasis added):
excerpt from Answer: Tuples are compared position by position: the first item of first tuple is compared to the first item of the second tuple; if they are not equal, this is the result of the comparison, else the second item is considered, then the third and so on.
Which I understand for == comparisons. edit: *thought I understood
To generalize to all comparison operators I would modify the answer to be something like this:
... the first item of first tuple is compared to the first item of the second tuple; if the comaprison yields False then the result of the tuple comaprison is also False. Otherwise the comparison continues with the remaining items.... edit: this was wrong. Subtly wrong though, worked for == but not other relational operators.
I am having trouble seeing how that works for < (less than) comparisons. The python documentation they link to (modified to point to 2.7) also talks about this in terms of equality, not less than - again, emphasis added:
excerpt from python docs: Sequence types also support comparisons. In particular, tuples and lists are compared lexicographically by comparing corresponding elements. This means that to compare equal, every element must compare equal and the two sequences must be of the same type and have the same length. (For full details see Comparisons in the language reference.) edit: at this point when writing up my original question I had tunnel vision on 'equality'.
I found nothing helpful in the The Comparisons language reference; it doesn't touch on why ( 1, 2 ) < ( 1, 3 ) yields True when the comparison operator seems like it should yield False for the first pair of elements.
The following is some example output of a toy test program; most of it works as I would expect. Please note the 2 embedded questions.
Ouput from "tcomp.py" (source below).
$ python tcomp.py
tcomp.py
version= 2.7.12
--- empty tuples, intuitive, no surprises ---
() == () : True
() < () : False
() > () : False
--- single-item tuples, equal values: intuitive, no surprises ---
(1,) == (1,) : True
(1,) < (1,) : False
(1,) > (1,) : False
--- single-item diff: intuitive, no surprises ---
(1,) == (2,) : False
(1,) < (2,) : True
(1,) > (2,) : False
--- double-item same: intuitive, no surprises ---
(1, 2) == (1, 2) : True
(1, 2) < (1, 2) : False
(1, 2) > (1, 2) : False
* Question: do a<b and a>b both yield False
* because Python short circuits on
* a[0] < b[0] (and correspondingly a[0] > b[0] )?
* e.g. Python never bothers comparing second
* elements: a[1] < b[1] (and, correspondinlgy, a[1] > b[1] ).
--- double-item 1st=same 2nd=diff: ??? What is with a<b ???
(1, 2) == (1, 3) : False
(1, 2) < (1, 3) : True
(1, 2) > (1, 3) : False
* Question: Here I get the == comparison, that yields False like I would expect.
* But WHAT is going on with the < comparison?
* Even comapring "lexicographically", how does a[0] < b[0]
* actually yield True ?
* Is Python really comparing a[0] < b[0] ?
* Because in my mental model that is the same as comparing: 1 < 1
* I kind of think 1 < 1 is supposed to be False, even if Python
* is comparing "1" < "1" (e.g. lexicographically).
$
To add to the last "*Question" above, comapring a[0] < b[0] lexicographically would be like comparing '1' < '1' which still should be false, yes?
tcomp.py:
import platform
def tupleInfo( a, b, msg ):
# using labels instead of eval-style stuff to keep things simpler.
print
print '--- ' , msg , ' ---'
print a, ' == ', b, ' : ', a == b
print a, ' < ', b, ' : ', a < b
print a, ' > ', b, ' : ', a > b
print 'tcomp.py'
print 'version=', platform.python_version()
# let's start with some empty tuples.
e1 = tuple()
e2 = tuple()
tupleInfo( tuple( ) , tuple( ) , 'empty tuples,intuitive, no surprises' )
tupleInfo( tuple( [ 1 ] ) , tuple( [ 1 ] ) , 'single-item tuples, equal values: intuitive, no surprises' )
tupleInfo( tuple( [ 1 ] ) , tuple( [ 2 ] ) , 'single-item diff: intuitive, no surprises' )
tupleInfo( tuple( [ 1, 2 ] ), tuple( [ 1, 2 ] ), 'double-item same: intuitive, no surprises' )
print '* Question: do a<b and a>b both yield False '
print '* because Python short circuits on'
print '* a[0] < b[0] (and correspondingly a[0] > b[0] )?'
print '* e.g. Python never bothers comparing second'
print '* elements: a[1] < b[1] (and, correspondinlgy, a[1] > b[1] ).'
tupleInfo( tuple( [ 1, 2 ] ), tuple( [ 1, 3 ] ), 'double-item 1st=same 2nd=diff: ??? What is with a<b ???' )
print '* Question: Here I get the == comparison, that yields False like I would expect.'
print '* But WHAT is going on with the < comparison?'
print '* Even comapring "lexicographically", how does a[0] < b[0]'
print '* actually yield True ?'
print '* Is Python really comparing a[0] < b[0] ?'
print '* Because in my mental model that is the same as comparing: 1 < 1'
print '* I kind of think 1 < 1 is supposed to be False, even if Python'
print '* is comparing "1" < "1" (e.g. lexicographically).'