Aspire
Aspire

Reputation: 417

Custom sorting a deck of cards

I'm currently stuck on an assignment, where it asks to build a function and rank the suits in a certain order (♢,♣,♡,♠)

My code should end up returning this:

['10♢', '10♣', '10♡', '10♠', '2♢', '2♣', '2♡', '2♠', '3♢', '3♣', '3♡', '3♠', '4♢', '4♣', '4♡', '4♠', '5♢', '5♣', '5♡', '5♠', '6♢', '6♣', '6♡', '6♠', '7♢', '7♣', '7♡', '7♠', '8♢', '8♣', '8♡', '8♠', '9♢', '9♣', '9♡', '9♠', 'A♢', 'A♣', 'A♡', 'A♠', 'J♢', 'J♣', 'J♡', 'J♠', 'K♢', 'K♣', 'K♡', 'K♠', 'Q♢', 'Q♣', 'Q♡', 'Q♠']

Here is my code:

def helper_function(cards):
  value = 0
  for string in cards:
    if '♢' in string:
      value = 1
    if '♣' in string:
      value = 2
    if '♡' in string:
      value = 3
    if '♠' in string:
      value = 4

def card_sorter_v1(cards):
  return sorted(cards, key = helper_function)

I know I need to use custom comparisons, but I am not sure what else to put in the helper function to sort this deck. I cannot hard-code any values because the testing framework will include edge cases. Any tips or advice?

Here is the output I am currently receiving:

['A♢', '2♢', '3♢', '4♢', '5♢', '6♢', '7♢', '8♢', '9♢', '10♢', 'J♢', 'Q♢', 'K♢', 'A♣', '2♣', '3♣', '4♣', '5♣', '6♣', '7♣', '8♣', '9♣', '10♣', 'J♣', 'Q♣', 'K♣', 'A♡', '2♡', '3♡', '4♡', '5♡', '6♡', '7♡', '8♡', '9♡', '10♡', 'J♡', 'Q♡', 'K♡', '15♡', 'A♠', '2♠', '3♠', '4♠', '5♠', '6♠', '7♠', '8♠', '9♠', '10♠', 'J♠', 'Q♠', 'K♠']

Upvotes: 0

Views: 1012

Answers (5)

J.Doe
J.Doe

Reputation: 464

I don't know why this works, but here:

List = ['10♠', '10♡', '10♢', '10♣', '2♠', '2♡', '2♢',
        '2♣', '3♠', '3♡', '3♢', '3♣', '4♠', '4♡', '4♢',
        '4♣', '5♠', '5♡', '5♢', '5♣', '6♠', '6♡', '6♢',
        '6♣', '7♠', '7♡', '7♢', '7♣', '8♠', '8♡', '8♢',
        '8♣', '9♠', '9♡', '9♢', '9♣', 'A♠', 'A♡', 'A♢',
        'A♣', 'J♠', 'J♡', 'J♢', 'J♣', 'K♠', 'K♡', 'K♢',
        'K♣', 'Q♠', 'Q♡', 'Q♢', 'Q♣']


def val(ele):

    color = ele[-1]
    value = ele.replace(color,'')

    ord_color = ['♠','♡','♣','♢']
    ord_value = ['Q','K','J','A','9','8','7','6','5','4','3','2','10']

    rank = ord_color.index(color) + (ord_value.index(value)*len(ord_color))

    return rank


List.sort(key=val,reverse=True)

print(List)

Upvotes: 0

Mulham Jarjanazi
Mulham Jarjanazi

Reputation: 386

here I used two functions, one to sort the deck by numbers, and another to sort it by symbols:


cards = ['10♠', '10♡', '10♢', '10♣', '2♠', '2♡', '2♢', '2♣', '3♠', '3♡', '3♢', '3♣', '4♠', '4♡', '4♢', '4♣', '5♠', '5♡', '5♢', '5♣', '6♠', '6♡', '6♢', '6♣', '7♠', '7♡', '7♢', '7♣', '8♠', '8♡', '8♢', '8♣', '9♠', '9♡', '9♢', '9♣', 'A♠', 'A♡', 'A♢', 'A♣', 'J♠', 'J♡', 'J♢', 'J♣', 'K♠', 'K♡', 'K♢', 'K♣', 'Q♠', 'Q♡', 'Q♢', 'Q♣']


# sorts deck by number
def sort_by_number(cards):
    sort = ["10", "2", "3", "4", "5", "6", "7", "8", "9", "A", "J", "K", "Q"]
    sorted_deck = []
    for i in sort:
        for card in cards:
            if card[:-1] == i:
                sorted_deck.append(card)
    return sorted_deck


# sorts deck by symbol:
def sort_by_symbol(cards):
    cards = sort_by_number(cards)
    for i in range(0, len(cards)):
        current_num = cards[i][:-1]
        _0, _1, _2, _3 = 0, 0, 0, 0       
        for card in cards:
            if card[:-1] == current_num:
                if card[-1] == "♢":
                    _0 = card
                if card[-1] == "♣":
                    _1 = card
                if card[-1] == "♡":
                    _2 = card
                if card[-1] == "♠":
                    _3 = card
        cards[i:i+4] = [_0, _1, _2, _3]
    return cards 

Upvotes: 0

Mohsen_Fatemi
Mohsen_Fatemi

Reputation: 3401

I did not use a pythonic way to solve it, i just converted each card's rank to a number between 1 and 4, then i've wrote a bubble sort to sort the list :

def convert_card_to_number(card):
  if '♢' in card:
    return card[:-1]+'1'
  if '♣' in card:
    return card[:-1]+'2'
  if '♡' in card:
    return card[:-1]+'3'
  if '♠' in card:
    return card[:-1]+'4'

cards = ['10♠', '10♡', '10♢', '10♣', '2♠', '2♡', '2♢', '2♣', '3♠', '3♡', '3♢', '3♣', '4♠', '4♡', '4♢', '4♣', '5♠', '5♡', '5♢', '5♣', '6♠', '6♡', '6♢', '6♣', '7♠', '7♡', '7♢', '7♣', '8♠', '8♡', '8♢', '8♣', '9♠', '9♡', '9♢', '9♣', 'A♠', 'A♡', 'A♢', 'A♣', 'J♠', 'J♡', 'J♢', 'J♣', 'K♠', 'K♡', 'K♢', 'K♣', 'Q♠', 'Q♡', 'Q♢', 'Q♣']

for i in range(len(cards)):
   for j in range(i+1,len(cards)):
      if convert_card_to_number(cards[i])>convert_card_to_number(cards[j]):
         temp = cards[i]
         cards[i] = cards[j]
         cards[j] = temp

print(cards)

the output would be :

['10♢', '10♣', '10♡', '10♠', '2♢', '2♣', '2♡', '2♠', '3♢', '3♣', '3♡', '3♠', '4♢', 
'4♣', '4♡', '4♠', '5♢', '5♣', '5♡', '5♠', '6♢', '6♣', '6♡', '6♠', '7♢', '7♣', '7♡', 
'7♠', '8♢', '8♣', '8♡', '8♠', '9♢', '9♣', '9♡', '9♠', 'A♢', 'A♣', 'A♡', 'A♠', 'J♢', 
'J♣', 'J♡', 'J♠', 'K♢', 'K♣', 'K♡', 'K♠', 'Q♢', 'Q♣', 'Q♡', 'Q♠']

Upvotes: 0

jedwards
jedwards

Reputation: 30240

Here's one approach:

cards = ['10♠', '10♡', '10♢', '10♣', '2♠', '2♡', '2♢', '2♣', '3♠', '3♡', '3♢', '3♣', '4♠', '4♡', '4♢', '4♣', '5♠', '5♡', '5♢', '5♣', '6♠', '6♡', '6♢', '6♣', '7♠', '7♡', '7♢', '7♣', '8♠', '8♡', '8♢', '8♣', '9♠', '9♡', '9♢', '9♣', 'A♠', 'A♡', 'A♢', 'A♣', 'J♠', 'J♡', 'J♢', 'J♣', 'K♠', 'K♡', 'K♢', 'K♣', 'Q♠', 'Q♡', 'Q♢', 'Q♣']

SUIT_ORDER = {
    '♢': 0,
    '♣': 1,
    '♡': 2,
    '♠': 3,
}

RANK_ORDER = {str(r):r for r in range(2,11)}
RANK_ORDER.update(
    J = 11,
    Q = 12,
    K = 13,
    A = 14,
)

def helper(card):
    suit = SUIT_ORDER.get(card[-1:], 20)
    rank = RANK_ORDER.get(card[:-1], 20)
    return (suit, rank)

cards.sort(key=helper)
print(cards)

This uses dictionaries as mappings from either suit symbol or rank (as a string) to turn a card string into a 2-tuple of ("suit score", "rank score").

The helper function returns this tuple and sort uses the helper function as a sort key.

Results:

[
 '2♢', '3♢', '4♢', '5♢', '6♢', '7♢', '8♢', '9♢', '10♢', 'J♢', 'Q♢', 'K♢', 'A♢',
 '2♣', '3♣', '4♣', '5♣', '6♣', '7♣', '8♣', '9♣', '10♣', 'J♣', 'Q♣', 'K♣', 'A♣',
 '2♡', '3♡', '4♡', '5♡', '6♡', '7♡', '8♡', '9♡', '10♡', 'J♡', 'Q♡', 'K♡', 'A♡', 
 '2♠', '3♠', '4♠', '5♠', '6♠', '7♠', '8♠', '9♠', '10♠', 'J♠', 'Q♠', 'K♠', 'A♠'
]

Edit:

I changed the default of the get calls to 20, a number higher than any valid card. You don't need to do this (and could simply use RANK_ORDER[card[-1:]]) but this way your program will still function with invalid suits or ranks, and the sort will place them at the end.

(Using [] indexing would result in a KeyError for invalid cards and .get() with the default default of None would result in a TypeError when you went to sort.)

Edit 2:

My code should end up returning this: ['10♢', '10♣', '10♡', '10♠', '2♢', '2♣', '2♡', '2♠', '3♢', '3♣', '3♡', '3♠', '4♢', '4♣', '4♡', '4♠', '5♢', '5♣', '5♡', '5♠', '6♢', '6♣', '6♡', '6♠', '7♢', '7♣', '7♡', '7♠', '8♢', '8♣', '8♡', '8♠', '9♢', '9♣', '9♡', '9♠', 'A♢', 'A♣', 'A♡', 'A♠', 'J♢', 'J♣', 'J♡', 'J♠', 'K♢', 'K♣', 'K♡', 'K♠', 'Q♢', 'Q♣', 'Q♡', 'Q♠']

If that's what you really want, your key function can be a lot simpler:

def helper(card):
    suit = SUIT_ORDER.get(card[-1:], 20)
    rank = card[:-1]
    return (rank, suit)

Upvotes: 1

wgb22
wgb22

Reputation: 247

You can use string slicing to break up the card and suit:

for card in cards:
    (card[:-1], card[-1])

The first element of the tuple is the card; the second element is the suit. I recommend making helper functions for both. I see you are already doing that for the suit, but you will also need it for the card to deal with the picture cards.

Then check out this answer to see how to sort a list of tuples: How does operator.itemgetter and sort() work in Python?

Upvotes: 0

Related Questions