Sorting with a python dictionary - python

I have a dictionary of "documents" in python with document ID numbers as keys and dictionaries (again) as values. These internal dictionaries each have a 'weight' key that holds a floating-point value of interest. In other words:
documents[some_id]['weight'] = ...
What I want to do is obtain a list of my document IDs sorted in descending order of the 'weight' value. I know that dictionaries are inherently unordered (and there seem to be a lot of ways to do things in Python), so what is the most painless way to go? It feels like kind of a messy situation...

I would convert the dictionary to a list of tuples and sort it based on weight (in reverse order for descending), then just remove the objects to get a list of the keys
l = documents.items()
l.sort(key=lambda x: x[1]['weight'], reverse=True)
result = [d[0] for d in l]

I took the approach that you might want the keys as well as the rest of the object:
# Build a random dictionary
from random import randint
ds = {} # A |D|ata |S|tructure
for i in range(20,1,-1):
ds[i]={'weight':randint(0,100)}
sortedDS = sorted(ds.keys(),key=lambda x:ds[x]['weight'])
for i in sortedDS :
print i,ds[i]['weight']
sorted() is a python built in that takes a list and returns it sorted (obviously), however it can take a key value that it uses to determine the rank of each object. In the above case it uses the 'weight' value as the key to sort on.
The advantage of this over Ameers answer is that it returns the order of keys rather than the items. Its an extra step, but it means you can refer back into the original data structure

This seems to work for me. The inspiration for it came from OrderedDict and question #9001509
from collections import OrderedDict
d = {
14: {'weight': 90},
12: {'weight': 100},
13: {'weight': 101},
15: {'weight': 5}
}
sorted_dict = OrderedDict(sorted(d.items(), key=lambda rec: rec[1].get('weight')))
print sorted_dict

Related

Keeping a dictionary (or similar structure) ordered in Python

I need to work with two data structures that inherit all the properties of dictionaries in Python3.8. But I want these dictionaries to be ordered with respect to the key every time I insert an element. One dictionary has to keep an ascending order while the other a descending order.
For example, consider the two dictionaries
dic1 = {1:'a',2:'b',3:'c',5:'e'} #This dictionary needs to keep the order of ascending keys
dic2 = {5:'e', 3:'c',2:'b',1:'a'} #This dictionary needs to keep the order of ascending keys
and let's add an element to both of them
dic1[4]='d'
dic2[4]='d'
After these operations, I want the two dictionaries to be
> dic1 == {1:'a',2:'b',3:'c',4:'d',5:'e'} #This dictionary needs to keep the order of ascending keys
> True
> dic2 == {5:'e', 4:'d', 3:'c',2:'b',1:'a'} #This dictionary needs to keep the order of ascending keys
> True
without having to sort the dictionaries through dict(sorted(dic1)) or dict(sorted(dic2,reverse=True)).
I know that I can define dic1to be a SortedDictfrom sortedcontainers. However, in the documentation of sortedcontainers.SortedDictI cannot find how to define the order of the keys (ascending or descending).
Any insight?
The documentation has exactly the example of what you're trying to do:
>>> sd = SortedDict(neg, enumerate('abc', start=1))
>>> sd
SortedDict(<built-in function neg>, {3: 'c', 2: 'b', 1: 'a'})
>>> keys = sd.keys()
>>> list(keys)
[3, 2, 1]

Python: How to sort a dictionary of X and Y coordinates by ascending X coordinate value?

I have the following dictionary that I would like to sort based on their X coordinate in ascending fashion so that I can identify the "beacon" by the color arrangement (RGB in different orders). I keep trying to sort it like a list but that's not working out too well. Thanks in advance :)
Beacon2 = {
'r': [998.9282836914062, 367.3825378417969],
'b': [985.82373046875, 339.2225646972656],
'g': [969.539794921875, 369.2041931152344]
}
For this specific dictionary the expected result is
sortedBeacon = {
'g': [969.539794921875, 369.2041931152344],
'b': [985.82373046875, 339.2225646972656],
'r': [998.9282836914062, 367.3825378417969]
}
Note that dictionaries in general are not sortable. You can generate the internals sorted however without any lambdas by using itemgetter:
from operator import itemgetter
sorted_d = sorted(d.items(), key=itemgetter(1))
If you really want to maintain order, wrap the above in an OrderedDict
The method sort() in Python is normally used on lists and tuples whereas sorted() is better for data structures like dictionaries.
In this case, using a simple lambda function can help you get what you want.
print(sorted(Beacon2.values(), key = lambda x: (x[0]))
You can try this:
from collections import OrderedDict
Beacon2 = {'r': [998.9282836914062, 367.3825378417969], 'b':
[985.82373046875, 339.2225646972656], 'g': [969.539794921875, 369.2041931152344]}
sorted_beacons = sorted(Beacon2.items(), key = lambda x: x[1][0])
>>> print(OrderedDict(sorted_beacons))
OrderedDict([('g', [969.539794921875, 369.2041931152344]), ('b', [985.82373046875, 339.2225646972656]), ('r', [998.9282836914062, 367.3825378417969])])
Where you first sort the list of tuples from Beacon2.items(), with a sorting key applied on the X coordinate located at [1][0] of each tuple.
Note that you need to wrap an OrderedDict to your result to preserve order of the dictionary.
If you just want the values, use this:
sorted(data.values())
If you want the keys associated with the sorted values, use this:
sorted(data, key=data.get)
Both key and values:
sorted(data.items(), key=lambda x:x[1])
Courtesy of: sort dict by value python

Compare value in dict with other values

I'd like to compare all entries in a dict with all other entries – if the values are within a close enough range, I want to merge them under a single key and delete the other key. But I cannot figure out how to iterate through the dict without errors.
An example version of my code (not the real set of values, but you get the idea):
things = { 'a': 1, 'b': 3, 'c': 22 }
for me in things.iteritems():
for other in things.iteritems():
if me == other:
continue
if abs(me-other) < 5:
print 'merge!', me, other
# merge the two into 'a'
# delete 'b'
I'd hope to then get:
>> { 'a': [ 1, 2 ], 'c': 22 }
But if I run this code, I get the first two that I want to merge:
>> merge! ('a', 1) ('b', 2)
Then the same one in reverse (which I want to have merged already):
>> duplicate! ('b', 2) ('a', 1)
If I use del things['b'] I get an error that I'm trying to modify the dict while iterating. I see lots of "how to remove items from a dict" questions, and lots about comparing two separate dicts, but not this particular problem (as far as I can tell).
EDIT
Per feedback in the comments, I realized my example is a little misleading. I want to merge two items if their values are similar enough.
So, to do this in linear time (but requiring extra space) use an intermediate dict to group the keys by value:
>>> things = { 'fruit': 'tomato', 'vegetable': 'tomato', 'grain': 'wheat' }
>>> from collections import defaultdict
>>> grouper = defaultdict(list)
>>> for k, v in things.iteritems():
... grouper[v].append(k)
...
>>> grouper
defaultdict(<type 'list'>, {'tomato': ['vegetable', 'fruit'], 'wheat': ['grain']})
Then, you simply take the first item from your list of values (that used to be keys), as the new key:
>>> {v[0]:k for k, v in grouper.iteritems()}
{'vegetable': 'tomato', 'grain': 'wheat'}
Note, dictionaries are inherently unordered, so if order is important, you should have been using an OrderedDict from the beginning.
Note that your result will depend on the direction of the traversal. Since you are bucketing data depending on distance (in the metric sense), either the right neighbor or the left neighbor can claim the data point.

Python support sorted dictionary -- similar to C++ map?

I am using Python 2.7.x. I have a dictionary (I mean {}), key is int and value is string. I want to retrieve the key which has the minimal integer value. In C++, I think we can use map, which sort keys. And in Python, not sure if anything similar we can leverage? If my understanding is correct, Python dictionary (I mean {}) is not sorted by key.
thanks in advance,
Lin
Update
The OP has expressed a need for O(1) performance when finding the minimum key in a dictionary. Try the sortedcontainers module. It offers a SortedDict class:
>>> from sortedcontainers import SortedDict
>>> d = SortedDict({100: 'a', 27: 'b', 1234: 'c'})
>>> d.keys()
SortedSet([27, 100, 1234], key=None, load=1000)
>>> d.keys()[0]
27
>>> d[d.keys()[0]]
'b'
For a Python builtin dictionary you can use min(d) to find the lowest key:
>>> d = {100: 'a', 27: 'b', 1234: 'c'}
>>> print(d)
{1234: 'c', 27: 'b', 100: 'a'}
>>> print(min(d))
27
>>> print(d[min(d)])
b
In Python, dictionaries are represented internally by hash tables so you cannot natively get back the keys in sorted order. You can use sorted(d.keys()) to return a list of keys in sorted order. You can also use collections.OrderedDict if you pre-sort the keys. If you do not know the order of the keys ahead of time and you need to maintain the keys in sorted order as you insert values, you could take a look at this library for the SortedDict type.
There are binary tree implementations in Python:
https://pypi.python.org/pypi/bintrees/2.0.2
You can also use the blist.sorteddict.
You could also use the built-in bisect module to maintain a sorted list of tuples.
If all you care about is finding the minimum and you don't actually care about maintaining a sort, you can use the built-in heapq module to maintain a min-heap data structure which gives you constant time access to the minimal element.
Building off of #mhawke 's answer, you can simply do:
d = {1 : "a", 2 : "b", 3 : "c" }
print d[min(d.keys())] # => 'a'

Combining indefinite number of dictionaries for python

I'm a novice python programmer and I'm stuck on a homework problem.
I want to combine dictionaries (tried using **dict) without using the update() method because I want to keep any duplicate keys. I'm fine with having some keys with multiple values.
Could someone point me in the right direction?
Also, I'm doing this in python 3.3
A dict maps a key to a value. Not multiple values. Thus, you need to make each value in the combined dict be a combination of all the values from the input dicts. The easiest way is to use a collections.defaultdict(list):
import collections
input_dicts = [{1: 0}, {1: 1}, {1: 2}]
output_dict = collections.defaultdict(list)
for d in input_dicts:
for key in d:
output_dict[key].append(d[key])
A collections.defaultdict calls a function you specify to generate a default value for any key that you try to access that doesn't already have a value. A collections.defaultdict(list) is thus a dict with default values of lists for all keys. This code will produce an output dict mapping keys to lists of all values from the input dicts.
You can't have duplicate keys in a dictionary. The keys must be unique, but I think what you're looking for is a defaultdict
from collections import defaultdict
d = defaultdict(list)
d1 = {1:'hi', 2:'hey', 3:'hai'}
d2 = {1:'hello', 2:'cabbage', 3:'greetings'}
for k, v in d1.items():
d[k].append(v)
for k1, v1 in d2.items():
d[k1].append(v1)
print d
Prints:
defaultdict(<type 'list'>, {1: ['hi', 'hello'], 2: ['hey', 'cabbage'], 3: ['hai', 'greetings']})

Categories

Resources