Reputation: 26325
I have two lists:
card_candidates = ['9D', '9S', '3S', '0D']
card_order = ['2', '3', '4', '5', '6', '7', '8', '9', '0', 'J', 'Q', 'K', 'A']
I want to be able to sort the first list with respect to the second lists order. So the sorted card_candidates should look like this:
sorted_candidates = ['3S', '9D', '9S', '0D']
The '0' is just the value of 10, just wanted to make all the cards the same length. If there is a tie, like with '9D' and '9S', then the letters will need to be sorted instead. So far I have just done this:
sorted_candidates = []
for x, y in zip(card_candidates, card_order):
sorted_candidates.append([x[0] for x in card_candidates])
return sorted(sorted_candidates)
I know that this is not even close to being right, I just don't know how to do this.
Upvotes: 1
Views: 2210
Reputation: 6756
You don't necessarily need any additional data structures, the card_order
list is totally enough to sort your cards using this simple one-liner:
card_candidates = ['9D', '9S', '3S', '0D']
card_order = ['2', '3', '4', '5', '6', '7', '8', '9', '0', 'J', 'Q', 'K', 'A']
sorted_cards = sorted(card_candidates, key=lambda c: (card_order.index(c[0]), c[1]))
print(list(sorted_cards))
Output:
['3S', '9D', '9S', '0D']
See this code running on ideone.com
Please note that this approach scans the card_order
list once for every card to sort each time you sort any card list. This is no problem if you just sort a normal deck of cards at the beginning of a game or even every few seconds. However, if your code is sorting huge numbers of cards or sorting cards most of its time, you might want to prefer the solution by Martijn Pieters which converts the card_order
list into a dictionary that can be scanned faster.
Upvotes: 2
Reputation: 1124040
Produce a dictionary mapping your sort order characters to a number, we'll sort by those:
sort_map = {c: i for i, c in enumerate(card_order)}
You can now use this mapping to sort your cards, including the second letter to break ties:
sorted_candidates = sorted(card_candidates,
key=lambda card: (sort_map[card[0]], card[1]))
The sort key takes the first character of each card and translates that to an integer from the sort_map
dictionary, which then inform the sorted()
function of the correct sort order. In case of a tie (equal card value), cards are sorted in clubs, diamonds, hearts, spades order (assuming you use C
and H
for clubs and hearts).
Creating a mapping up front keeps the sort within O(NlogN) time complexity; you could do the same with card_order.index(card[0])
, but then you invoke a list.index()
call for every sorted element, and list.index
needs to scan the list, producing a O(KNlogN) sort (where K is the length of the card_order
list).
Demo:
>>> card_candidates = ['9D', '9S', '3S', '0D']
>>> card_order = ['2', '3', '4', '5', '6', '7', '8', '9', '0', 'J', 'Q', 'K', 'A']
>>> sort_map = {c: i for i, c in enumerate(card_order)}
>>> sorted(card_candidates, key=lambda card: (sort_map[card[0]], card[1]))
['3S', '9D', '9S', '0D']
>>> sorted(['9D', '9S', '9C', '9H'], key=lambda card: (sort_map[card[0]], card[1]))
['9C', '9D', '9H', '9S']
Upvotes: 11