4

is it possible to sort a python dictionary by value if the value is a list, and I want it to be sorted by the first value of that list. E.G:

data = {
"Joe" : [1, "Joe", "password", "Joe@Email.com"], 
"Toby" : [2, "Toby", "password", "Toby@Email.com"], 
"John" : [4, "John", "password", "John@Email.com"], 
"Julie" : [3, "Julie", "password", "Julie@Email.com"]
}

I would like it to be like: Where 'i' is the key

for i in range(len(data)):
    print("UserID: ", str(data[i][0]), ". Username: ", data[i][1])

>> UserID: 1. Username: Joe
>> UserID: 2. Username: Toby
>> UserID: 3. Username: Julie
>> UserID: 4. Username: John

Many thanks.

JoeTilsed
  • 111
  • 1
  • 1
  • 4

2 Answers2

6

You cannot sort a dict in place, because Python dicts are unordered. You have at least 2 alternatives :

Create a sorted list of tuples

You can use sorted with a key= argument. In this case, it would be the first element of the dict value :

sorted(data.items(), key= lambda x: x[1][0])
# [('Joe', [1, 'Joe', 'password', 'Joe@Email.com']), ('Toby', [2, 'Toby', 'password', 'Toby@Email.com']), ('Julie', [3, 'Julie', 'password', 'Julie@Email.com']), ('John', [4, 'John', 'password', 'John@Email.com'])]

It returns a sorted list of tuples, which you can use to iterate and print the result :

data = {
    "Joe": [1, "Joe", "password", "Joe@Email.com"],
    "Toby": [2, "Toby", "password", "Toby@Email.com"],
    "John": [4, "John", "password", "John@Email.com"],
    "Julie": [3, "Julie", "password", "Julie@Email.com"]
}

for name, lst in sorted(data.items(), key=lambda x: x[1][0]):
    print("UserID : %d. Username : %s" % (lst[0], name))

# UserID : 1. Username : Joe
# UserID : 2. Username : Toby
# UserID : 3. Username : Julie
# UserID : 4. Username : John

Create an OrderedDict

If you want to sort data and keep the functionality of a dict, you can create an OrderedDict :

from collections import OrderedDict

data = {
    "Joe": [1, "Joe", "password", "Joe@Email.com"],
    "Toby": [2, "Toby", "password", "Toby@Email.com"],
    "John": [4, "John", "password", "John@Email.com"],
    "Julie": [3, "Julie", "password", "Julie@Email.com"]
}

data = OrderedDict(sorted(data.items(), key=lambda x: x[1][0]))
# OrderedDict([('Joe', [1, 'Joe', 'password', 'Joe@Email.com']), ('Toby', [2, 'Toby', 'password', 'Toby@Email.com']), ('Julie', [3, 'Julie', 'password', 'Julie@Email.com']), ('John', [4, 'John', 'password', 'John@Email.com'])])

Note : For both examples, key=lambda x: x[1] would also be enough.

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • 1
    Downvoters : Constructive criticism is welcome. I dare say both my suggestions are correct. – Eric Duminil Mar 13 '17 at 15:02
  • I like your answer. As a minor siggestion, returning the list as the key to compare is enough, returning the first element of it is not needed, as iterable are compared item by item. – Adirio Mar 13 '17 at 15:43
3

You can use itemgetter, this should sort the entries by the list (you can sort lists of lists and it will by default sort by the first element). This will give back a list of tuples, with the first element being the key, which you can loop through and print.

import operator

data = {
"Joe" : [1, "Joe", "password", "Joe@Email.com"], 
"Toby" : [2, "Toby", "password", "Toby@Email.com"], 
"John" : [4, "John", "password", "John@Email.com"], 
"Julie" : [3, "Julie", "password", "Julie@Email.com"]
}


sorted_data = sorted(data.items(), key=operator.itemgetter(1))

for entry in (sorted_data):
    print("UserID: " + str(entry[1][0]) + ". Username: " + entry[0])

Output:

UserID: 1. Username: Joe
UserID: 2. Username: Toby
UserID: 3. Username: Julie
UserID: 4. Username: John

Note: The reason sorted_data is a list of tuples instead of a dictionary is that python dictionaries are inherently unordered. See answers to this for an explanation: Why is python ordering my dictionary like so?

Community
  • 1
  • 1
Kewl
  • 3,327
  • 5
  • 26
  • 45
  • There's no need to import operator in this case, which just hides the logic behind for casual python coders. – Adirio Mar 13 '17 at 15:44
  • Okay, I've rewritten it using the same logic but without using operator – Kewl Mar 13 '17 at 17:28
  • Why? At least I learned something with your first, correct and concise code. Now we basically have the same answer. You'll get my vote if you revert your edit. – Eric Duminil Mar 13 '17 at 17:40
  • 1
    Haha okay, I've reverted - guess I should learn I can't please everyone :P – Kewl Mar 13 '17 at 17:54
  • Saying that there is no need does nto mean that is not correct. I would not select is as the accepted answer as I think the first is cleaner, but this offers an alternative solution. – Adirio Mar 14 '17 at 09:00