Arthur Pennt
Arthur Pennt

Reputation: 155

Correcting a list with a dictionary and a subsequent .sort() command displays wrong string order

sorry for the bad title. I am new to programming and I could not come up with a better description.

So, I have this code:

umw = {'T':10, 'J':11, 'Q':12, 'K':13, 'A':14}

def card_ranks(ranks):
    "Return a list of the ranks, sorted with higher first."
    for i in ranks:
        if i in umw:
            index = ranks.index(i)
            ranks[index] = str(umw[i])

    ranks.sort(reverse = True)
    return ranks

print(card_ranks(['A', '3', '4', 'K'])) #should output [14, 13, 4, 3]

This gives me the following result:

['4', '3', '14', '13']

clearing the "reverse = True" gives the following:

['13', '14', '3', '4']

If i do something like that:

r = card_ranks(['A', '3', '4', 'K'])
r[0] -> gives me '4'
but this doesnt work again:
print(sorted(r)) -> gives me ['4', '3', '14', '13'] all over again.

So it seems, that the .sort() command views the 13 & 14 as a unit and the 3 & 4.

Could somebody explain why that is?

Thanks alot!

Upvotes: 2

Views: 68

Answers (5)

user2390182
user2390182

Reputation: 73470

You are sorting strings where '11' comes before '3'. The following sorted call deals with the necessary type conversion:

def card_ranks(ranks):
    return sorted((umw[c] if c in umw else int(c) for c in ranks), reverse=True)

>>> card_ranks(['A', '3', '4', 'K'])
[14, 13, 4, 3]

For every string in ranks, the generator expression produces the corresponding value in the umw dict or, as fallback, turns the string into an int, such that a proper numerical, non-lexicographical comparison is possible.

Upvotes: 3

Jai
Jai

Reputation: 3300

  • Because the list elements are string that's why
  • while sorting its taking in account every character i.e. every digit in the number
  • Which means every string char is sorted by its first character and then by its next character
  • Which means "233" < "3" and "1111" < "233"

    umw = {'T':10, 'J':11, 'Q':12, 'K':13, 'A':14}
    
    def card_ranks(ranks):
        "Return a list of the ranks, sorted with higher first."
        for i in ranks:
            if i in umw:
                index = ranks.index(i)
                ranks[index] = str(umw[i])
        ranks = list(map(int, ranks))   # The line to be added
        ranks.sort(reverse = True)
        return ranks
    
    print(card_ranks(['A', '3', '4', 'K'])) #sh
    
    • You need to convert the list elements to int by ranks = list(map(int, ranks)) before sorting the list

Upvotes: 1

Patrick Haugh
Patrick Haugh

Reputation: 61032

You're sorting them lexicographically, as strings rather than numbers. You could convert them to integers first, or you could expand your umw dictionary:

umw = {str(i): i for i in range(2, 10)}
umw.update({'T':10, 'J':11, 'Q':12, 'K':13, 'A':14})

def card_ranks(ranks):
    return sorted(ranks, key=umw.get, reverse=True)

card_ranks(['A', '3', '4', 'K'])
# ['A', 'K', '4', '3']

This uses the dict.get method as a key function to guide the sorting without changing the values being sorted.

Upvotes: 6

mrjaso
mrjaso

Reputation: 51

ranks[index] = str(umw[i])

You are saving the values as strings instead of integers. And it is sorting them as strings.

Try

ranks[index] = int(umw[i])

Upvotes: 0

MegaIng
MegaIng

Reputation: 7886

It does not see them as a unit, it compares the charakter for charakter: '1'<'3'<'4', so the ranking is '13'<'14'<'3'<'4'

You want all of them to be numbers, so change the following lines:

ranks[index] = str(umw[i])

to

ranks[index] = umw[i]

and:

print(card_ranks(['A', '3', '4', 'K']))

to

print(card_ranks(['A', 3, 4, 'K']))

Upvotes: 1

Related Questions