954,525 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Dictionary Sorting By Values Other Than Keys

Hello everyone,

I'm learning Python and I have a few questions about Dictionaries and sorting them by a value other than the key.

Lets say, for example, I have a Dictionary full of data that needs to be sorted on the 3rd value instead of the key. How would I go about doing this? I have tried just the .sort() and that just sorts by the key.

So if,

Data = [('1023', ['Name', '3.1', 'SomeData']), ('1000', ['SomeName', '4.0', 'MoreData'])

how would I sort "Data" by the value where 3.1 is?

Please forgive my lack of correct terminology if I am missing some somewhere! Any help would be greatly appreciated.

xm1014
Newbie Poster
6 posts since Apr 2008
Reputation Points: 10
Solved Threads: 0
 

It doesn't look like you're using a dictionary. It appears that you have a list of tuples, and each tuple consists of a string and a list.

I can't think of a built in way to do this. You might have to look at writing your own version of a bubble sort or something. To do that, you would go through the entire outer list and compare the 2nd element of the inner list. If they are not in the correct order, then switch them around. Repeat until you can go through the whole list without having to make any switches.

mn_kthompson
Junior Poster
148 posts since Nov 2007
Reputation Points: 16
Solved Threads: 35
 

You can use the 'key' argument to 'sort' or 'sorted'. Here, Data is a list. You can write

def my_key(item):
    return item[1][1] # this returns 3.1 if item is ('1023', ['Name', '3.1', 'SomeData'])

Data.sort(key = my_key)

Data is easily turned into a dictionary:

Data = dict(Data)
L = sorted(Data.items(), key = my_key)
Gribouillis
Posting Maven
Moderator
2,786 posts since Jul 2008
Reputation Points: 1,044
Solved Threads: 691
 

Similar to Gribouillis' code, but uses lambda as a helper function ...

# sort a more complex combination of lists/tuples:
mylist = [
(1, ['a', '3.1', 'ad']),
(2, ['b', '4.0', 'bd']),
(3, ['c', '2.5', 'cd']),
]
# sort by item at index [1][1] of each tuple
# using a helper function like lambda
newlist = sorted(mylist, key=lambda tup: tup[1][1])

print newlist

"""my result (made pretty) -->
[
(3, ['c', '2.5', 'cd']),
(1, ['a', '3.1', 'ad']), 
(2, ['b', '4.0', 'bd'])
]
"""
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

You can also use a somewhat older concept of sorting, the Schwartzian transform algorithm. This is made very easy with Python's list comprehension ...

# sort a more complex combination of lists/tuples:
    
mylist = [
(1, ['a', '3.1', 'ad']),
(2, ['b', '4.0', 'bd']),
(3, ['c', '2.5', 'cd']),
]

# use the Schwartzian transform algorithm
# temporarily put a copy of indexed item in front
templist = [(x[1][1], x) for x in mylist]
templist.sort()
# remove temporary front item after sorting
newlist = [val for (temp, val) in templist]

print newlist

"""my result (made pretty) -->
[
(3, ['c', '2.5', 'cd']),
(1, ['a', '3.1', 'ad']), 
(2, ['b', '4.0', 'bd'])
]
"""
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

I've tried all three of these methods, however, I haven't been able to get them to work correctly for my particular set of data. I believe I may have pasted my dictionary incorrectly.

Here is what I have in my dictionary:
data = {'1234': ['Matt', '2.5', 'CS'], '1000': ['John', '4.0', 'Music'], '1023': ['Aaron', '3.1', 'PreMed'], '1001': ['Paul', '3.9', 'Music'], '9000': ['Kris', '3.5', 'Business']}

Would this have affected the methods of sorting that were mentioned?

xm1014
Newbie Poster
6 posts since Apr 2008
Reputation Points: 10
Solved Threads: 0
 

So you have a dictionary after all!

Dictionaries are indexed by key and the keys are in a hash order for fast lookups. They will always display in this order! If you want to sort by a certain item, you have to convert them to lists. I thought that is what you did.

data_dict = {
'1234': ['Matt', '2.5', 'CS'], 
'1000': ['John', '4.0', 'Music'], 
'1023': ['Aaron', '3.1', 'PreMed'], 
'1001': ['Paul', '3.9', 'Music'], 
'9000': ['Kris', '3.5', 'Business']
}

# convert dictionary to a list of tuples
data_list = [(key, val) for key, val in data_dict.items()]

print(data_list)
"""the raw list -->
[
('1234', ['Matt', '2.5', 'CS']), 
('9000', ['Kris', '3.5', 'Business']), 
('1001', ['Paul', '3.9', 'Music']), 
('1023', ['Aaron', '3.1', 'PreMed']), 
('1000', ['John', '4.0', 'Music'])
]
"""

# now you can sort the list by item[1][1]
sorted_list = sorted(data_list, key=lambda tup: tup[1][1])

print(sorted_list)
"""result sorted by item[1][1] -->
[
('1234', ['Matt', '2.5', 'CS']), 
('1023', ['Aaron', '3.1', 'PreMed']), 
('9000', ['Kris', '3.5', 'Business']), 
('1001', ['Paul', '3.9', 'Music']), 
('1000', ['John', '4.0', 'Music'])]
"""

# however if you go back to a dictionary
new_dict = dict(sorted_list)

print(new_dict)
"""result is the dictionary order again -->
{
'1234': ['Matt', '2.5', 'CS'], 
'1000': ['John', '4.0', 'Music'], 
'1001': ['Paul', '3.9', 'Music'], 
'1023': ['Aaron', '3.1', 'PreMed'], 
'9000': ['Kris', '3.5', 'Business']}
"""


So, if you want to do any processing that needs a sorted order, to have to convert your dictionary to a temporary list.

vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

Ah ha! That worked! Now, since you're putting it in a list to sort the values, is there also a way to separate those values you are sorting on into a list by themselves?

xm1014
Newbie Poster
6 posts since Apr 2008
Reputation Points: 10
Solved Threads: 0
 
Ah ha! That worked! Now, since you're putting it in a list to sort the values, is there also a way to separate those values you are sorting on into a list by themselves?


Is this what you mean?

>>> my_dict = {'a':1, 'b':2, 'c':3}
>>> my_dict.keys()
['a', 'c', 'b']
>>> my_dict.values()
[1, 3, 2]
>>>
jlm699
Veteran Poster
1,112 posts since Jul 2008
Reputation Points: 355
Solved Threads: 292
 

Is this what you mean?

>>> my_dict = {'a':1, 'b':2, 'c':3}
>>> my_dict.keys()
['a', 'c', 'b']
>>> my_dict.values()
[1, 3, 2]
>>>

Not exactly, I'd like to take the values that are being sorted on and put them into a new list/dict etc.

For example, extracting only these values from the dictionary above:
new_list = ('2.5','3.5','3.9','4.0','3.1')

xm1014
Newbie Poster
6 posts since Apr 2008
Reputation Points: 10
Solved Threads: 0
 

Not exactly, I'd like to take the values that are being sorted on and put them into a new list/dict etc.

For example, extracting only these values from the dictionary above: new_list = ('2.5','3.5','3.9','4.0','3.1')


Okay... how about this:

>>> data_dict = {
... '1234': ['Matt', '2.5', 'CS'], 
... '1000': ['John', '4.0', 'Music'], 
... '1023': ['Aaron', '3.1', 'PreMed'], 
... '1001': ['Paul', '3.9', 'Music'], 
... '9000': ['Kris', '3.5', 'Business']
... }
>>> [data[1] for data in data_dict.values()]
['2.5', '3.5', '3.9', '3.1', '4.0']
>>>

That's just a quick list comprehension that will extract the second element (at index 1) from each list (which is stored as the "value" part of each dictionary entry.

jlm699
Veteran Poster
1,112 posts since Jul 2008
Reputation Points: 355
Solved Threads: 292
 

Hah, this thread nudged me in studying more on sorting (more complex data structures) with Python. So I took a swing at it. These are the ones I came up with:

data = {'1234': ['Matt', '2.5', 'CS'],
        '1000': ['John', '4.0', 'Music'],
        '1023': ['Aaron', '3.1', 'PreMed'],
        '1001': ['Paul', '3.9', 'Music'],
        '9000': ['Kris', '3.5', 'Business']}

# Sort by name, print keys only.
print sorted(data, key=lambda x: data[x][0])

# Sort by name, print keys and values.
a = sorted(data, key=lambda x: data[x][0])
for i in a:
    print i, '->', data[i]

# Sort by name, print values only.
print map(data.get, sorted(data, key=lambda x: data[x][0]))

# Sort by names, print keys and values.
print ["%s -> %s" % (i, data.get(i)) for i in sorted(data, key=lambda x: data[x][0])]


These all sort by name, but you can change the 0 to 1 to sort by the GPA (at least that is what I think it is), and change it to 2 to sort by category/group (or whatever it is). I actually worked on this for at least an hour (maybe more, kind of lost track of time), just kept finding additional information or more interesting python methods.

Xydric
Newbie Poster
10 posts since Oct 2009
Reputation Points: 10
Solved Threads: 4
 

The nice thing about Xydric's approach is that it doesn't lose the important connectivity with the original dictionary via the keys ...

data = {
'1234': ['Matt', '2.5', 'CS'],
'1000': ['John', '4.0', 'Music'],
'1023': ['Aaron', '3.1', 'PreMed'],
'1001': ['Paul', '3.9', 'Music'],
'9000': ['Kris', '3.5', 'Business']
}

# sort by index in value, here GPA values at index 1
# gives a list of keys in that specified order
key_list = sorted(data, key=lambda x: data[x][1])

gpa_list = [data[key][1] for key in key_list]

print( gpa_list )  # ['2.5', '3.1', '3.5', '3.9', '4.0']

# now if you wanted to know who got the 2.5
# it should be the first key in the key_list too (at index=0)
print( data[key_list[0]] )     # ['Matt', '2.5', 'CS']
# or ...
print( data[key_list[0]][0] )  # Matt
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

The nice thing about Xydric's approach is that it doesn't lose the important connectivity with the original dictionary via the keys ...

data = {
'1234': ['Matt', '2.5', 'CS'],
'1000': ['John', '4.0', 'Music'],
'1023': ['Aaron', '3.1', 'PreMed'],
'1001': ['Paul', '3.9', 'Music'],
'9000': ['Kris', '3.5', 'Business']
}

# sort by index in value, here GPA values at index 1
# gives a list of keys in that specified order
key_list = sorted(data, key=lambda x: data[x][1])

gpa_list = [data[key][1] for key in key_list]

print( gpa_list )  # ['2.5', '3.1', '3.5', '3.9', '4.0']

# now if you wanted to know who got the 2.5
# it should be the first key in the key_list too (at index=0)
print( data[key_list[0]] )     # ['Matt', '2.5', 'CS']
# or ...
print( data[key_list[0]][0] )  # Matt


I couldn't get the syntax on the print (data[key_list[0]) to work, should there be another "]" there?

Also, could you use this method, for example, to search by "major"? So if you wanted a list of 'Music', how would you go about this?

xm1014
Newbie Poster
6 posts since Apr 2008
Reputation Points: 10
Solved Threads: 0
 

I couldn't get the syntax on the print (data[key_list[0]) to work, should there be another "]" there?

Also, could you use this method, for example, to search by "major"? So if you wanted a list of 'Music', how would you go about this?

If you look at my code with a sharp eye you will find that all [] match.

On part 2 ...

# sorted() handles dictionaries directly
# for indexed sorting

data = {
'1234': ['Matt', '2.5', 'CS'],
'1000': ['John', '4.0', 'Music'],
'1023': ['Aaron', '3.1', 'PreMed'],
'1001': ['Paul', '3.9', 'Music'],
'9000': ['Kris', '3.5', 'Business']
}

# sort by index in value, here by 'Major' at index 2
# gives a list of keys in that specified order
key_list = sorted(data, key=lambda x: data[x][2])

major_list = [data[key][2] for key in key_list]

print( major_list )  # ['Business', 'CS', 'Music', 'Music', 'PreMed']

# optionally create a sub dictionary of all the music majors
music_major_dict = dict([(key, data[key]) \
    for key in key_list if data[key][2] == 'Music'])

print( music_major_dict )
"""
{'1001': ['Paul', '3.9', 'Music'], '1000': ['John', '4.0', 'Music']}
"""
vegaseat
DaniWeb's Hypocrite
Moderator
5,989 posts since Oct 2004
Reputation Points: 1,345
Solved Threads: 1,417
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You