0

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♠']

Aspire
  • 397
  • 1
  • 3
  • 9
  • The [key functions](https://docs.python.org/3/howto/sorting.html#key-functions) section of the Sorting How-To might be of interest. You can use your helper function as the sort key and (with a little modification to take into account the rank of the card, _and return a value_), you should be good to go. – jedwards Oct 07 '19 at 22:26
  • 1
    `helper_function` will take a single card. It needs to return a value which can be used for ordering. You aren't returning anything, and you assume the whole deck is passed as a parameter. – Peter Wood Oct 07 '19 at 22:44

5 Answers5

1

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)
jedwards
  • 29,432
  • 3
  • 65
  • 92
  • Ah, that worked. Thanks! We haven't covered array slicing in our class yet, so I'm a bit confused on the code. How does the suit = SUIT_ORDER.get(card[-1:], 20) and rank = card[:-1] work exactly? – Aspire Oct 07 '19 at 22:53
  • Slicing (both for lists and strings) is covered thoroughly [here](https://stackoverflow.com/questions/509211/understanding-slice-notation/509295), but basically, in this case `card[-1:]` selects the substring from the last character of `card`, until the end (which in this case is just the last character and could have been written `card[-1]`). Similarly, `card[:-1]` selects the substring from the start of the string until (but not including) the last character. – jedwards Oct 08 '19 at 01:36
0

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?

wgb22
  • 247
  • 1
  • 13
  • @Aspire Your question isn't a specific programming question and I worry it may be shut down by a moderator. Can you consider re-phrasing it to ask a specific programming question? Try add in code that you are using to call the helper function and show any error messages or unexpected output. – wgb22 Oct 07 '19 at 22:39
0

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♠']
Mohsen_Fatemi
  • 2,183
  • 2
  • 16
  • 25
0

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 

0

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)
J.Doe
  • 224
  • 1
  • 4
  • 19