Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: unorderable types: tuple() < int() in Python 3

The below code is ordering poker hands. It works well in Python 2.7 but it does not work in Python 3. What are the changes that have been made causing it to give an TypeError: unorderable types: tuple() < int()?

def poker(hands):
    scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]
    winner = sorted(scores , key=lambda x:x[1])[-1][0]
    return hands[winner]

def score(hand):
    ranks = '23456789TJQKA'
    rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()
    score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])
    if len(score) == 5:
        if ranks[0:2] == (12, 3): #adjust if 5 high straight
            ranks = (3, 2, 1, 0, -1)
        straight = ranks[0] - ranks[4] == 4
        flush = len({suit for _, suit in hand}) == 1
        '''no pair, straight, flush, or straight flush'''
        score = ([1, (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
    return score, ranks

 >>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS'])
 '8C AD 8D AC 9C'
like image 423
Nickpick Avatar asked Mar 15 '23 16:03

Nickpick


2 Answers

It is happening because you are comparing int and a tuple. In python2x, default cmp operation was defined for different inbuilt objects, which has been removed in python3.

Python 3 ignores the cmp() method. In addition to this, the cmp() function is gone! This typically results in your converted code raising a TypeError: unorderable types error. So you need to replace the cmp() method with rich comparison methods instead. To support sorting you only need to implement lt(), the method used for the “less then” operator, <.

Official documentation

So, in python2, we can do something like this

(2, 3) > 2

but it raises TypeError in python3. If this code was working in python2, then most probably it was bug that was implicitly being handled by default comparison behaviour.

Now in your example:-

#value of scores that are being compared for sorting
scores = [(0, (1, (11, 8, 7, 6, 2))), (1, (1, (12, 5, 3, 1, 0))), (2, ((2, 2, 1), (12, 6, 7))), (3, (1, (11, 8, 6, 5, 3)))]

print(type(scores[1][1][0])) # <class 'int'>
print(type(scores[2][1][0])) # <class 'tuple'>

which as I have explained does not work in python3. What is the criteria you are assuming for comparing a tuple and an int.

If you really want to compare different type of objects, then you need to roll out your own version of tuple, and use that object in your scores instead.

class MyTuple(tuple):

     def __lt__(self, other):
        pass

Default tuple comparison python 2

Note:- I don't recommend using this approach. It was just for instructional purposes.

like image 180
hspandher Avatar answered Mar 27 '23 17:03

hspandher


The solution: Convert the integer into a tuple: score = ([(1, ), (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]

like image 20
Nickpick Avatar answered Mar 27 '23 15:03

Nickpick