Python 3 sort a dict by its values [duplicate] - python

This question already has answers here:
How do I sort a dictionary by value?
(34 answers)
Closed last month.
The only methods I found work for python2 or return only list of tuples.
Is it possible to sort dictionary, e.g. {"aa": 3, "bb": 4, "cc": 2, "dd": 1}, by its values?
Order of sorted dictionary I want to achieve is from largest to smallest. I want results to look like this:
bb 4
aa 3
cc 2
dd 1
And after sorting I want to store it into a text file.

itemgetter (see other answers) is (as I know) more efficient for large dictionaries but for the common case, I believe that d.get wins. And it does not require an extra import.
>>> d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
>>> for k in sorted(d, key=d.get, reverse=True):
... k, d[k]
...
('bb', 4)
('aa', 3)
('cc', 2)
('dd', 1)
Note that alternatively you can set d.__getitem__ as key function which may provide a small performance boost over d.get.

from collections import OrderedDict
from operator import itemgetter
d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
print(OrderedDict(sorted(d.items(), key = itemgetter(1), reverse = True)))
prints
OrderedDict([('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)])
Though from your last sentence, it appears that a list of tuples would work just fine, e.g.
from operator import itemgetter
d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
for key, value in sorted(d.items(), key = itemgetter(1), reverse = True):
print(key, value)
which prints
bb 4
aa 3
cc 2
dd 1

You can sort by values in reverse order (largest to smallest) using a dictionary comprehension:
{k: d[k] for k in sorted(d, key=d.get, reverse=True)}
# {'b': 4, 'a': 3, 'c': 2, 'd': 1}
If you want to sort by values in ascending order (smallest to largest)
{k: d[k] for k in sorted(d, key=d.get)}
# {'d': 1, 'c': 2, 'a': 3, 'b': 4}
If you want to sort by the keys in ascending order
{k: d[k] for k in sorted(d)}
# {'a': 3, 'b': 4, 'c': 2, 'd': 1}
This works on CPython 3.6+ and any implementation of Python 3.7+ because dictionaries keep insertion order.

Another way is to use a lambda expression. Depending on interpreter version and whether you wish to create a sorted dictionary or sorted key-value tuples (as the OP does), this may even be faster than the accepted answer.
d = {'aa': 3, 'bb': 4, 'cc': 2, 'dd': 1}
s = sorted(d.items(), key=lambda x: x[1], reverse=True)
for k, v in s:
print(k, v)

To sort dictionary, we could make use of operator module. Here is the operator module documentation.
import operator #Importing operator module
dc = {"aa": 3, "bb": 4, "cc": 2, "dd": 1} #Dictionary to be sorted
dc_sort = sorted(dc.items(),key = operator.itemgetter(1),reverse = True)
print dc_sort
Output sequence will be a sorted list :
[('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)]
If we want to sort with respect to keys, we can make use of
dc_sort = sorted(dc.items(),key = operator.itemgetter(0),reverse = True)
Output sequence will be :
[('dd', 1), ('cc', 2), ('bb', 4), ('aa', 3)]

To sort a dictionary and keep it functioning as a dictionary afterwards, you could use OrderedDict from the standard library.
If that's not what you need, then I encourage you to reconsider the sort functions that leave you with a list of tuples. What output did you want, if not an ordered list of key-value pairs (tuples)?

Related

Sort a dict according to both key and value at the same time [duplicate]

This question already has answers here:
Sort a list by multiple attributes?
(7 answers)
Closed 1 year ago.
I have a dict that looks like this:
{0: 2, 1: 4, 2: 2, 3: 2, 4: 5}
That is, both the keys and values integers.
I need to sort this dict in this way:
By the value first, ascending;
by the key, if the values ties, descending.
All I know is that python's sorted() function supports a parameter called "key" but it seems that it just allows to have either key or value at once.
What can I do to achieve?
FYI, the result should be like:
{2: 2, 0: 2, 3: 2, 1: 4, 4: 5}
There's not an easy way to say "this value, ascending, then this one, descending". However, if you negate each of a list of integers, then sort it, then that's the same as sorting it in reverse.
This defines a sorting key which is a tuple:
The first value is each dict item's value.
The second value is each dict item's key, but negated.
d = {0: 2, 2: 2, 3: 2, 1: 4, 4: 5}
def sort_key(item):
key, value = item
return value, -key
print(sorted(d.items(), key=sort_key))
This outputs:
[(3, 2), (2, 2), (0, 2), (1, 4), (4, 5)]
See? The items are grouped by value, and in the event of a tie, by key in descending order.
How do I sort a dictionary by value?
data = {0: 2, 1: 4, 2: 2, 3: 2, 4: 5}
sorted_data = dict(sorted(data.items(), key=lambda item:item[1]))
print(sorted_data)
output
{0: 2, 2: 2, 3: 2, 1: 4, 4: 5}
Dictionaries can't really be sorted, but since 3.6 they preserve insertion ordering, so you can create a new dictionary from the sorted tuple items of the previous dictionary.
To get what you want, you have to do this twice - once by key, then by value.
This works because python's sorted is guaranteed to be "stable" - if two items are identical then it won't change them, so the second value sort will preserve the initial key sort if two values match.
input_dictionary = {0: 2, 1: 4, 2: 2, 3: 2, 4: 5}
sorted_by_key = dict(sorted(input_dictionary.items(), key=lambda x: x[0], reverse=True))
sorted_by_both = dict(sorted(sorted_by_key.items(), key=lambda x: x[1]))
print(sorted_by_both)
Demo

Convert nested dictionary into list of tuples

I have a nested dictionary that looks like the following
db1 = {
'Diane': {'Laundry': 2, 'Cleaning': 4, 'Gardening': 3},
'Betty': {'Gardening': 2, 'Tutoring': 1, 'Cleaning': 3},
'Charles': {'Plumbing': 2, 'Cleaning': 5},
'Adam': {'Cleaning': 4, 'Tutoring': 2, 'Baking': 1},
}
The desired sorted dictionary looks like the following
[(5, [('Cleaning', ['Charles'])]),
(4, [('Cleaning', ['Adam', 'Diane'])]),
(3, [('Cleaning', ['Betty']), ('Gardening', ['Diane'])]),
(2, [('Gardening', ['Betty']), ('Laundry', ['Diane']),
('Plumbing', ['Charles']), ('Tutoring', ['Adam'])]),
(1, [('Baking', ['Adam']), ('Tutoring', ['Betty'])])]
it is a list of 2 tuples, the first index is the skill level sorted by decreasing level and the second index is another list of 2 tuple which contains their names as another list inside it. Do I need to extract info from the original dictionary and build a completely new list of tuples? Or I just need to simply change original dictionary into a list of 2 tuple
You can build up an intermediate dictionary, and then use it to produce your final output, as follows:
from pprint import pprint
db1 = {
'Diane': {'Laundry': 2, 'Cleaning': 4, 'Gardening': 3},
'Betty': {'Gardening': 2, 'Tutoring': 1, 'Cleaning': 3},
'Charles': {'Plumbing': 2, 'Cleaning': 5},
'Adam': {'Cleaning': 4, 'Tutoring': 2, 'Baking': 1},
}
d = {}
for k, v in db1.items():
for kk, vv in v.items():
if vv not in d:
d[vv] = {}
if kk not in d[vv]:
d[vv][kk] = []
d[vv][kk].append(k)
out = sorted([(k,
[(kk, sorted(v[kk])) for kk in sorted(v.keys())])
for k, v in d.items()],
key=lambda t:t[0],
reverse=True)
pprint(out)
Gives:
[(5, [('Cleaning', ['Charles'])]),
(4, [('Cleaning', ['Adam', 'Diane'])]),
(3, [('Cleaning', ['Betty']), ('Gardening', ['Diane'])]),
(2,
[('Gardening', ['Betty']),
('Laundry', ['Diane']),
('Plumbing', ['Charles']),
('Tutoring', ['Adam'])]),
(1, [('Baking', ['Adam']), ('Tutoring', ['Betty'])])]
(Note: it might be possible to use some kind of nested defaultdict to avoid the two if statements shown here, but I have not attempted this. If you did d=defaultdict(dict), that would avoid the first if statement, but the second would remain.)

Sorting OrderedDict entries according to keys in natural order [duplicate]

This question already has answers here:
Sort Dictionary Keys in natural order [duplicate]
(4 answers)
Sorting dictionary with alphanumeric keys in natural order [duplicate]
(2 answers)
Closed 3 years ago.
OrderedDict preserves the order in which entries were inserted into the dictionary. Given the OrderedDict such as:
{'a1': 1, 'a2':2, 'a14': 14, 'a3': 3}
it is possible to obtain the alphanumeric order with:
new_dic=OrderedDict(sorted(dic.items()))
{'a1': 1, 'a14': 14, 'a2': 2, 'a3':3}
However, is it possible to sort the entries according to keys in natural order such that the outcome is:
{'a1': 1, 'a2': 2, 'a3': 3, ..., 'a14': 14}
The purpose behind it is that I want to extract only the values of the dictionary but the values should be extracted according to the natural order of the keys.
Try this:
d = {'a1': 1, 'a14': 14, 'a3': 3, 'a2':2}
OrderedDict(sorted(d.items(), key=lambda (k, _): (k[0], int(k[1:]))))
=> OrderedDict([('a1', 1), ('a2', 2), ('a3', 3), ('a14', 14)])
# you could create a new dictionary:
import re
def atoi(text):
return int(text) if text.isdigit() else text
def natural_keys(text):
'''
alist.sort(key=natural_keys) sorts in human order
http://nedbatchelder.com/blog/200712/human_sorting.html
(See Toothy's implementation in the comments)
'''
return [ atoi(c) for c in re.split(r'(\d+)', text) ]
test = {'a1': 1, 'a14': 14, 'a3': 3, 'a2':2}
new_dict = {}
for k in sorted(test.keys(),key=natural_keys):
new_dict[k] = test[k]
editing to sort even if dictionary has multiple character starts. help from How to correctly sort a string with a number inside?

For each in list Python

Consider I have a tuple in Python
numbers = (('One', 1), ('Two', 2), ('Three', 3), ('Four', 4))
I want to create a numbers_dict in dictionary
numbers_dict = {}
for number in numbers:
numbers_dict[number[0]] = number[1]
and so I get
numbers_dict = {
'One': 1,
'Two': 2,
'Three': 3,
'Four': 4,
}
Can I do something simpler using the syntax
numbers_dict = [n[0] : n[1] for n in numbers]
?
Just pass numbers directly to the dict() type:
numbers_dict = dict(numbers)
From the documentation:
If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object. Otherwise, the positional argument must be an iterable object. Each item in the iterable must itself be an iterable with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value.
Your numbers tuple is such an iterable, and each element in it is a (key, value) pair.
Demo:
>>> numbers = (('One', 1), ('Two', 2), ('Three', 3), ('Four', 4))
>>> dict(numbers)
{'One': 1, 'Four': 4, 'Three': 3, 'Two': 2}
You could use a dictionary comprehension too, but that's really overkill here; only use that when you do something more meaningful for each key or value. But for completeness sake, that'd look like this:
numbers_dict = {k: v for k, v in numbers}

How to compare values inside a dictionary to fill up sets()

dico = {"dico": {1:"bailler",2:"bailler",3:"percer",4:"calculer",5:"calculer",6:"trouer",7:"bailler",8:"découvrir",9:"bailler",10:"miser",11:"trouer",12:"changer"}}
I have a big dictionary of dictionaries like that. I want to put identic elements together in sets. So create a kind of condition which will say if the values of "dico" are equal put them in a set():
b=[set(1,2,7,9),set(3),set(4,5),set(6,11),set(8),set(10),set(12)]
I don't know if that question has already been asked but as a new pythonner I don't have all the keys... ^^
Thank you for you answers
I would reverse your dictionary and have the value a set(), then return all the values.
>>> from collections import defaultdict
>>>>my_dict= {"dico": {1:"bailler",2:"bailler",3:"percer",4:"calculer",5:"calculer",6:"trouer",7:"bailler",8:"découvrir",9:"bailler",10:"miser",11:"trouer",12:"changer"}}
>>> my_other_dict = defaultdict(set)
>>> for dict_name,sub_dict in my_dict.iteritems():
for k,v in sub_dict.iteritems():
my_other_dict[v].add(k) #the value, i.e. "bailler" is now the key
#e.g. {"bailler":set([1,2,9,7]),...
>>> [v for k,v in my_other_dict.iteritems()]
[set([8]), set([1, 2, 9, 7]), set([3]), set([4, 5]), set([12]), set([11, 6]), set([10])]
Of course as cynddl has pointed out, if your index in a list will always be the "key", simply enumerate a list and you won't have to store original data as a dictionary, nor use sets() as indices are unique.
You should write your data this way:
dico = ["bailler", "bailler", "percer", "calculer", "calculer", "trouer", "bailler", "découvrir", "bailler", "miser", "trouer", "changer"]
If you want to count the number of identic elements, use collections.Counter:
import collections
counter=collections.Counter(dico)
print(counter)
which returns a Counter object:
Counter({'bailler': 4, 'calculer': 2, 'trouer': 2, 'd\xc3\xa9couvrir': 1, 'percer': 1, 'changer': 1, 'miser': 1})
The dict.setdefault() method can be handy for tasks like this, as well as dict.items() which iterates through the (key, value) pairs of the dictionary.
>>> dico = {"dico": {1:"bailler",2:"bailler",3:"percer",4:"calculer",5:"calcul
er",6:"trouer",7:"bailler",8:"découvrir",9:"bailler",10:"miser",11:"trouer",12:"
changer"}}
>>> newdict = {}
>>> for k, subdict in dico.items():
... newdict[k] = {}
... for subk, subv in subdict.items():
... newdict[k].setdefault(subv, set()).add(subk)
...
>>> newdict
{'dico': {'bailler': {1, 2, 9, 7}, 'miser': {10}, 'découvrir': {8}, 'calculer':
{4, 5}, 'changer': {12}, 'percer': {3}, 'trouer': {11, 6}}}
>>> newdict['dico'].values()
dict_values([{1, 2, 9, 7}, {10}, {8}, {4, 5}, {12}, {3}, {11, 6}])

Categories