Sorting dictionary both desceding and ascending in Python

Tags: python
Question!

I want to sort the dictionary by values. If the values are the same, then I want to sort it by keys.

For example, if I have the string "bitter butter a butter baggy", output has to be [(butter,2),(a,1),(baggy,1),(bitter,1)).

My below code sorts the dictionary by values in descending order. But I am not able to do the second part, i.e. if the values are same, then I have sort keys in ascending order.

Any help would be appreciated.

def count_words(s,n):
  words = s.split(" ")
  wordcount = {}
  for word in words:
   if word not in wordcount:
    wordcount[word] = 1
   else:
    wordcount[word] += 1
  sorted_x = sorted(wordcount.items(), key=operator.itemgetter(1), reverse=True)
  sorted_asc = sorted(wordcount.items(), key=operator.itemgetter(0))
 return sorted_x


Answers

For this, what you need is to write a comparator which sorts the values by count first and if they are equal then it sorts the values by the keys.

from collections import defaultdict


def count_words(s):
    def comparator(first, second):
        if first[1] > second[1]:
            return 1
        elif first[1] < second[1]:
            return -1

        if first[0] > second[0]:
            return -1
        elif first[0] == second[0]:
            return 0
        return 1

    words = s.split(" ")
    wordcount = defaultdict(int)

    for word in words:
        wordcount[word] += 1

    return sorted(wordcount.items(), cmp=comparator, reverse=True)


print count_words("bitter butter a c batter butter baggy")

[('butter', 2), ('a', 1), ('baggy', 1), ('batter', 1), ('bitter', 1), ('c', 1)]



I suppose this would help

s = { "A":1, "B":1,  "C":1, "D":0, "E":2, "F":0 }
rez = sorted(s.items(), key = lambda x: (x[1],x[0]))

Result is

[('D', 0), ('F', 0), ('A', 1), ('B', 1), ('C', 1), ('E', 2)]

If you need a reversed order, just use -x[1] instead of x[1]



C++11 solution:

#include <type_traits>

template<typename From, typename To>
To map(From e) {
    return static_cast<To>(
        static_cast<typename std::underlying_type<To>::type>(
        static_cast<typename std::underlying_type<From>::type>(e)));
}

This casting cascade is very explicit and supports enum classes.

For older C++ versions and for enums without class, static_cast<Enum2>(e) would suffice.

Edit:

With template specialization, you can use map without specifying any types explicitly:

enum class Enum1: int {A, B, C, D};
enum class Enum2: char {A1, B1, C1, D1};

template<typename T>
struct target_enum {
};

template<>
struct target_enum<Enum1> {
    typedef Enum2 type;
};

template<typename From>
typename target_enum<From>::type map(From e) {
    typedef typename target_enum<From>::type To;
    return static_cast<To>(
        static_cast<typename std::underlying_type<To>::type>(
        static_cast<typename std::underlying_type<From>::type>(e)));
}

You can then call map(Enum1::A). Also works with simple, non-class enums.

By : flyx


This video can help you solving your question :)
By: admin