-1

I'm a newbie to python. I'm trying to solve a problem.Lets assume I'm getting a log file with identifier followed by space separated words. I need to sort the log based on words (identifiers can be omitted). However if the words match I need to sort based on identifier. So I'm building a dictionary with identifier being key and words being value. For simplicity, I'm using sample example below. How can I sort a dictionary by value and then sort by key if the values match? Below is an example.

>>> a_dict = {'aa1':'n','ba2' : 'a','aa2':'a'}
>>> a_dict
{'ba2': 'a', 'aa1': 'n', 'aa2': 'a'}

If I sort the given dictionary by value, it becomes this.

>>> b_tuple = sorted(a_dict.items(),key = lambda x: x[1])
>>> b_tuple                                                                                                                                                                                                                                  
[('ba2', 'a'), ('aa2', 'a'), ('aa1', 'n')]

However the expected output should look like this

[('aa2', 'a'), ('ba2','a'), ('aa1', 'n')]

The reason being if values are same the dictionary has to be sorted by key. Any suggestions as to how this can be done?

Ani
  • 149
  • 1
  • 1
  • 8

2 Answers2

4

The key function in your example only sorts by value, as you've noticed. If you also want to sort by key, then you can return the value and key (in that order) as a tuple:

>>> sorted(a_dict.items(), key=lambda x: (x[1], x[0]))
[('aa2', 'a'), ('ba2', 'a'), ('aa1', 'n')]

The confusing part is that your data looks like ('aa2', 'a'), for example, but it is being sorted as ('a', 'aa2') because of (x[1], x[0]).

cr3
  • 461
  • 3
  • 8
  • Can you please explain how the above code works?x[1] and x[0] denotes priority in which order has to be maintained? – Ani Apr 16 '18 at 22:39
  • @Ani I provided more details in my answer, don't hesitate to ask if it's still not clear. – cr3 Apr 16 '18 at 22:54
2

You can use an OrderedDict from the collections module to store your sorted value

from collections import OrderedDict
a_dict = {'aa1':'n','ba2' : 'a','aa2':'a'}
sorted_by_key_then_value = sorted(a_dict.items(), key=lambda t: (t[1], t[0])))
sort_dict = OrderedDict(sorted_by_key_then_value)

EDIT: I mix up key and value in (t[0], t[1]). In the key function t[0] give the key, and t[1] give the value. The sorted function will use the tuple(value, key) and order them by alphanumerical order.

TwistedSim
  • 1,960
  • 9
  • 23
  • 1
    Probably not a good idea, ordered dictionary keeps a linked list internally, which is heavy on the memory if you have a lot of elements. – Bubble Bubble Bubble Gut Apr 16 '18 at 22:36
  • 1
    I found this post which explains quite well the pros and cons: https://stackoverflow.com/a/18951209/9655255 – TwistedSim Apr 16 '18 at 22:46
  • 1
    @Ding there’s no mention of performance requirements, an OrderedDict is in the standard library, so why is it “bad”? Maybe instead you could comment, “if you didn’t already know, and memory matters...”. Because your comment is insightful, and it did inform me, at least. Thank you. – Zach Young Apr 16 '18 at 23:22