简体   繁体   中英

sort dict by value then if equal by keys

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

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)]

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)))

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM