Sort cards according to their suites and values using python

Question:

Can anybody help me to sort the cards by suite and value?
I have:

list_cards = [('♥', '9'), ('♥', 'J'), ('♦', 'J'), ('♥', '7'), ('♥', '10'), ('♦', '10')]

and I need to get:

[('♥', '7'), ('♥', '9'), ('♥', '10'),('♥', 'J'), ('♦', '10'), ('♦', 'J')]

I tried such methods:

return list_cards.sort(key=lambda c: (NAME_TO_VALUE[c[0]], c[1]))
return sorted(list_cards, key=lambda c: (NAME_TO_VALUE[c[0]], c[1]))
return sorted(list_cards)

and so on…

but the result differs from that I wanted to get.
Here is the full code:

NOMINALS = ['7', '8', '9', '10', 'J', 'Q', 'K', 'A']
NAME_TO_VALUE = {n: i for i, n in enumerate(NOMINALS)} -> :<class 'dict'>: {'7': 0, '8': 1, '9': 2, '10': 3, 'J': 4, 'Q': 5, 'K': 6, 'A': 7}
list_cards = [('♥', '9'), ('♥', 'J'), ('♦', 'J'), ('♥', '7'), ('♥', '10'), ('♦', '10')]

def sort_hand():
    # return list_cards.sort(key=lambda c: (NAME_TO_VALUE[c[0]], c[1]))
    # return sorted(list_cards, key=lambda c: (NAME_TO_VALUE[c[0]], c[1]))
    return sorted(list_cards)
Asked By: Vladimir

||

Answers:

One way is to simply use helper functions to convert cards to and from ordinal positions, then use those ordinal positions for sorting.

For example:

# These decide sort order, change if different order needed.

suitMap = ['♠', '♣', '♦', '♥']
faceMap = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']

def cardToOrd(cardVal):
    return 13 * suitMap.index(cardVal[0]) + faceMap.index(cardVal[1])

def ordToCard(ordVal):
    return (suitMap[ordVal // 13], faceMap[ordVal % 13])

def sortCards(cardList):
    newList = [cardToOrd(i) for i in cardList]
    newList.sort()
    return [ordToCard(i) for i in newList]

cards = [('♥', '9'), ('♥', 'J'), ('♦', 'J'), ('♥', '7'), ('♥', '10'), ('♦', '10')]
print(cards)
print(sortCards(cards))

You could make it a little more robust if there’s a chance invalid cards may be used. Changing the ordinal conversion functions as per below will force invalid cards to ('?', '?') and place them at the end:

def cardToOrd(cardVal):
    try:
        return 13 * suitMap.index(cardVal[0]) + faceMap.index(cardVal[1])
    except:
        return 99999

def ordToCard(ordVal):
    try:
        return (suitMap[ordVal // 13], faceMap[ordVal % 13])
    except:
        return ('?', '?')

As an aside, this is probably something I’d put into a class (e.g., cardset or deck), so I could collect all card processing code into a single coherent object. I’ll leave that as an exercise for the reader 🙂

Answered By: paxdiablo

Maybe you could create a couple dictionaries that store the order of the suits and ranks that you want, assuming you know the cards will be valid:

SUITS = ['♥', '♦', '♠', '♣']
RANKS = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
SUIT_ORDER = {suit: order for order, suit in enumerate(SUITS)}
RANK_ORDER = {rank: order for order, rank in enumerate(RANKS)}

list_cards = [('♥', '9'), ('♥', 'J'), ('♦', 'J'), ('♥', '7'), ('♥', '10'), ('♦', '10'), ('♠', '6'), ('♣', 'A')]
sorted_list_cards = sorted(list_cards, key=lambda c: (SUIT_ORDER[c[0]], RANK_ORDER[c[1]]))
print(sorted_list_cards)

Output:

[('♥', '7'), ('♥', '9'), ('♥', '10'), ('♥', 'J'), ('♦', '10'), ('♦', 'J'), ('♣', 'A'), ('♠', '6')]
Answered By: Sash Sinha
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.