Home > Back-end >  sort dict by value then if equal by keys
sort dict by value then if equal by keys

Time:01-31

i created a dict, keys=words in list values=count of them. Want to sort them by counts(values) THEN if counts equal sort them by alpha(keys)

a = [to, be, or, not, to, be, ae, ae]
w={}
for i in a:
    w[i]=a.count(i)
e=dict(sorted(w.items(),key= lambda a: (a[1],a[0]),reverse=True))
for i, k in e.items():
    print(i , k)

what i get now is

to 2
be 2
ae 2
or 1
not 1

and what i want is

ae 2
be 2
to 2
not 1
or 1 

im noob

CodePudding user response:

reverse=true applies to both elements of the tuple. That why your alphanumeric output is backwards.

To reverse the order on the first element of the tuple but not on the other you could negate the numbers:

sorted(w.items(),key= lambda a: (-a[1],a[0]))

If you ever run into problem where you need to sort on multiple tuple elements with varying ASC/DESC order and elements that are not easy to negate like integers you could use the following technique.

Modified multisort from https://docs.python.org/3/howto/sorting.html#sort-stability-and-complex-sorts

Since the sorting is stable the following will work:

def multisort(xs, specs):
     for i, reverse in reversed(specs):
         xs.sort(key=lambda x: x[i], reverse=reverse)
     return xs

items = [('to', 2), ('be', 2), ('or', 1), ('not', 1), ('ae', 2)]
multisort(items, [(0, False), (1, True)])

Output:

[('ae', 2), ('be', 2), ('to', 2), ('not', 1), ('or', 1)]

CodePudding user response:

I would use a custom sorted key and also a collections.Counter instance!

from collections import Counter

a = ['to', 'be', 'or', 'not', 'to', 'be', 'ae', 'ae']

for word, count in sorted(
    Counter(a).items(), key=lambda c: (-c[1], c[0])
):
    print(word, count)

CodePudding user response:

The problem is that the reverse keyword is too blunt for what you want: sorted sorts by the tuple, then reverses the result. You only want to reverse sort by the integer. Luckily, you can do that by simply negating each integer. (This trick obviously does not work for arbitrary values.)

e = dict(sorted(w.items(), key=lambda a: (-a[1], a[0])))

In general, you can write your own comparison function:

# 1 means x < y
# -1 means x > y
# 0 means x == y
def compare(x, y):
    if x[1] < y[1]:
        return 1
    elif x[1] > y[1]:
        return -1
    elif x[0] < y[0]:
        return -1
    elif x[0] > y[0]:
        return 1
    else:
        return 0
       

then use (functools.cmp_to_key)[https://docs.python.org/3/library/functools.html#functools.cmp_to_key]:

from functools import cmp_to_key

e = dict(sorted(w.items(), key=cmp_to_key(compare)))
  •  Tags:  
  • Related