1

I know this has been asked before, but I'm looking for a cleaner solution if there is one. I want to sort a hand of cards by suit and order.

Here's is the pertinent part of my Deck class:

import card
import random

class Deck:

    def __init__(self):
        suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
        values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" ,"A"]

        self._cards = [card.Card(suit, value) for suit in suits for value in values]

    def deal_hand(self):
        hand = random.sample(self._cards, 5)
        for card in hand:
            self._cards.remove(card)
        hand.sort(key=lambda x: (x.suit, x.value))
        return hand

Here's my card class:

class Card:

    def __init__(self, suit, value):
        self.suit = suit
        self.value = value

    def __repr__(self):
        return f"{self.value} of {self.suit}"

However, when I look at the players' hands, they are only sorted by suit, and not by value.

Here is the output I'm getting:

John's hand: [10 of Clubs, 2 of Clubs, A of Hearts, 9 of Spades, J of Spades]

Arnold's hand: [K of Clubs, 8 of Diamonds, 7 of Hearts, 9 of Hearts, 7 of Spades]

Alex's hand: [Q of Clubs, 2 of Hearts, 5 of Hearts, 8 of Spades, K of Spades]

Morgan's hand: [5 of Clubs, A of Diamonds, 10 of Hearts, Q of Hearts, 2 of Spades]

Where 10 of Clubs comes before 2 of Clubs. Also, K of x will come before Q of x.

Why is my lambda only sorting by suit? I would at least expect 10 of Clubs to come after 2 of Clubs.

Is there a clean solution?

rbb091020
  • 37
  • 1
  • 1
  • 10
  • 1
    you saved values as strings. so, lambda sorted them as strings. and in strings/lexographical sorting order, "1" comes before "2", but so does "10", or "100" etc. – Paritosh Singh Mar 13 '19 at 17:17
  • 1
    It's because `card.value` is a *string*. And strings are sorted in lexicographic (dictionary) order, so "10" comes before "2" which comes before "A". Edit: jinx. – alkasm Mar 13 '19 at 17:17
  • 1
    10 of clubs comes before 2 of clubs when sorted lexicografically. – Christian Sloper Mar 13 '19 at 17:17
  • Check out `"10" < "2"` – juanpa.arrivillaga Mar 13 '19 at 17:18
  • So I could just typecast them to ints? That would at least handle 10 coming before other numbers, right? How would I handle the face cards Q before K? – rbb091020 Mar 13 '19 at 17:19
  • 1
    Possible duplicate of [Does Python have a built in function for string natural sort?](https://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort) – Austin Mar 13 '19 at 17:20
  • 1
    @rbb091020 you *use more abstraction* of course. Create a class to represent the face values, and define the order. `enum`'s are perfectly ... suited for this. Check out a sketch I gave of such a solution: https://stackoverflow.com/questions/42398725/how-can-i-compare-the-values-of-two-playing-cards-when-they-have-a-value-and-a-s/42399384#42399384 – juanpa.arrivillaga Mar 13 '19 at 17:22
  • Just create a rank list enumerating your `values` which can contain the int values as index of values – mad_ Mar 13 '19 at 17:24
  • An easy way to modify your current classes is to have "value" be numeric, i.e. J is 11, A is 14, and have a "face" or "display" or something attribute for the JQKA strings. – alkasm Mar 13 '19 at 18:06

0 Answers0