How does tuple comparison work in Python?
Asked Answered
M

4

253

I have been reading the Core Python programming book, and the author shows an example like:

(4, 5) < (3, 5) # Equals false

So, I'm wondering, how/why does it equal false? How does python compare these two tuples?

Btw, it's not explained in the book.

Murmurous answered 13/3, 2011 at 20:52 Comment(0)
S
274

Tuples are compared position by position: the first item of the first tuple is compared to the first item of the second tuple; if they are not equal (i.e. the first is greater or smaller than the second) then that's the result of the comparison, else the second item is considered, then the third and so on.

See Common Sequence Operations:

Sequences of the same type 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.

Also Value Comparisons for further details:

Lexicographical comparison between built-in collections works as follows:

  • For two collections to compare equal, they must be of the same type, have the same length, and each pair of corresponding elements must compare equal (for example, [1,2] == (1,2) is false because the type is not the same).
  • Collections that support order comparison are ordered the same as their first unequal elements (for example, [1,2,x] <= [1,2,y] has the same value as x <= y). If a corresponding element does not exist, the shorter collection is ordered first (for example, [1,2] < [1,2,3] is true).

If not equal, the sequences are ordered the same as their first differing elements. For example, cmp([1,2,x], [1,2,y]) returns the same as cmp(x,y). If the corresponding element does not exist, the shorter sequence is considered smaller (for example, [1,2] < [1,2,3] returns True).

Note 1: < and > do not mean "smaller than" and "greater than" but "is before" and "is after": so (0, 1) "is before" (1, 0).

Note 2: tuples must not be considered as vectors in a n-dimensional space, compared according to their length.

Note 3: referring to question https://mcmap.net/q/109710/-how-does-tuple-comparison-work-in-python: do not think that a tuple is "greater" than another only if any element of the first is greater than the corresponding one in the second.

Note 4: as @david Winiecki mentioned in the comments, in case of two tuples of different length, the first one which reaches its end, being the previous part equal, is declared as the lower: (1, 2) < (1, 2, 3), since 1=1, 2=2 and then the first tuple ends

Selfconsistent answered 13/3, 2011 at 20:58 Comment(17)
This can be misleading when talking about < and >. For example, (0, 1) < (1, 0) evaluates to True.Squirt
@CMCDragonkai -- yes. try: x = tuple([0 for _ in range(n)]) and do the same for y. Setting n=100, 1000, 10,000, and 100,000 and running %timeit x==y gave timing values of .5, 4.6, 43.9, and 443 microseconds respectively, which is about as close to O(n) as you can practically get.Coterie
@J.Money why do you think it can be misleading?Selfconsistent
@J.Money wait I'm confused. The answer seems to imply that they are compared element-wise but that example seems they are compared based to first position.Compile
@Selfconsistent to me its confusing because that example seems to imply that the comparison is based on the first element while your answer seems to imply they are compared element-wise.Compile
@CharlieParker < and > do not mean "smaller then" and "greater then" but "comes before" and "comes after": so (0, 1) "comes before" (1, 0)Selfconsistent
@Selfconsistent I guess its not clear to we what type of ordering to impose on a tuple. I guess python just treats it as numbers by checking the largest significant digit first and the moving on to break dies...(in an element wise fashion)Compile
It IS less than. That's why -2<-1. The meaning isn't changed; tuples are just big-endian. The same as numbers: 01 IS less than 10.Rebuild
What does it mean "tuples must not be considered as coordinates in a n-dimensional space!"?Selfservice
@J.Money It's very practical because tuples can be placed into more complex data structures like heap and be compared by first value. Interestingly enough you also get stable sort as a bonus in some cases.Braun
Note: (1, 2) < (1, 2, 3) is True but (1, 3) < (1, 2, 3) is False. I can't find anything here or in documentation that makes this clear, but it's what I observe with Python 3.11.4.Nirvana
@DavidWiniecki, thank you for this addition. I updated my answer to address this caseSelfconsistent
I think the new addition "...in case of two tuples of different length, the first one which reaches its end is declared as the lower..." seems to imply the opposite of what I was trying to communicate. The length of the tuples is not the only thing that determines which tuple is greater. (1, 3) < (1, 2, 3) is False, meaning that (1, 3) is not less than (1, 2, 3), even though it is shorter. It seems like Python compares the i-th element of each tuple one at a time, starting with the first element, and when one of those pairs of elements is not equal, then the tuple that provided...Nirvana
...the smaller element is considered the smaller tuple. If Python reaches the end of one of the tuples before finding any pairs that are not equal, then the shorter tuple is considered the smaller tuple. Like I said above, I can't find anything here or in documentation that makes this clear, but it's what I observe with Python 3.11.4.Nirvana
I know it's not relevant to the question but I really want to say that it seems like comparing tuples of different lengths implicitly like this seems like a risky thing to do. It's probably better to always compare tuples of the same length, and if it seems very likely that tuples could be different lengths, then an assert should be used to assert that they are the same length, or their lengths should be explicitly compared, or the tuples should both be explicitly sliced to the same length and the resulting tuples should be compared.Nirvana
@DavidWiniecki, that's what I tried to convey, but you use better words!Selfconsistent
I think the "being the previous part equal" part you added helps a lot!Nirvana
J
32

The Python documentation does explain it.

Tuples and lists are compared lexicographically using comparison of corresponding elements. This means that to compare equal, each element must compare equal and the two sequences must be of the same type and have the same length.

Jara answered 13/3, 2011 at 20:57 Comment(2)
The page now linked from this answer does not seem to contain the text quoted.Bulkhead
I believe a better link to the quoted text is: docs.python.org/3/reference/expressions.html#value-comparisons . One does need to scroll down a bit to find the quoted text, but with the given link one must scroll up, which is unexpected and most would probably not do that.Invigorate
B
1

The python 2.5 documentation explains it well.

Tuples and lists are compared lexicographically using comparison of corresponding elements. This means that to compare equal, each element must compare equal and the two sequences must be of the same type and have the same length.

If not equal, the sequences are ordered the same as their first differing elements. For example, cmp([1,2,x], [1,2,y]) returns the same as cmp(x,y). If the corresponding element does not exist, the shorter sequence is ordered first (for example, [1,2] < [1,2,3]).

Unfortunately that page seems to have disappeared in the documentation for more recent versions.

Bulkhead answered 10/3, 2020 at 16:11 Comment(0)
P
0
I had some confusion before regarding integer comparsion, so I will explain it to be more beginner friendly with an example

a = ('A','B','C') # see it as the string "ABC" b = ('A','B','D')

A is converted to its corresponding ASCII ord('A') #65 same for other elements

So, >> a>b # True you can think of it as comparing between string (It is exactly, actually)

the same thing goes for integers too.

x = (1,2,2) # see it the string "123" y = (1,2,3) x > y # False

because (1 is not greater than 1, move to the next, 2 is not greater than 2, move to the next 2 is less than three -lexicographically -)

The key point is mentioned in the answer above

think of it as an element is before another alphabetically not element is greater than an element and in this case consider all the tuple elements as one string.

Pigfish answered 1/2, 2019 at 18:15 Comment(3)
(1,2,3) > (1,2,2) gives TrueRoussillon
(20,2) > (9,30) gives True, but 202 is not > 930, so for integers, it's comparing by position, not just concatenation.Spiker
Your explanation that the comparison works as it does because2 is less than 3 lexicographically is incorrect. Try again with numbers like 11 and 3. Each pair of elements by position are compared using the __gt__ method for that data type. For example, while 11 > 2 is True for integers, '11' > '2' is False for strings. Likewise for tuples, (11, 33) > (2, 4) is True while ('11', '33') > ('2', '4') is False. The word "lexicographic" usually means "treat all character strings as strings, even those that depict numbers". Tuple elements that aren't strings aren't treated as strings.Suspense

© 2022 - 2024 — McMap. All rights reserved.