Keeping a dictionary (or similar structure) ordered in Python - 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]

Related

python : how to order lists of dictionary values alphabetically, keeping to order of the dictionary the same, not sorting the dict by value

Is there an easy way to reorder a list of values in a dictionary alphabetically while keeping the order of the keys the same? I'm not looking to sort the dictionary by values just alphabetically order the lists of them. Thanks
Assuming you just didn't care about the old data ordering, you could just run this function:
def alphabetizeDictValues(dictionary):
for key in dictionary:
dictionary[key].sort()
The sort function of a list sorts the list in-place (making it lossy), so this would only work if you didn't care about the old ordering. This means that the memory requirement is lower, but also means you don't have a reference to how your list was previously sorted. Alternatively, if you wanted to save the old ordering, you could create this function
def alphabetizeDictValues(dictionary):
dupeDictionary = {}
for key in dictionary:
oldLst = list(dictionary[key])
dupeDictionary[key] = oldLst
dictionary[key].sort()
return dupeDictionary
This would return a copy of the input dictionary (with lists not sorted) while the dictionary you passed in would be the sorted version.
Assuming you want to sort the values independently of the keys (which can change the key: value association), you can create a new dictionary:
d = {'b': 1, 'c': 0, 'a': 2}
d2 = dict(zip(d, sorted(d.values())))
Output: {'b': 0, 'c': 1, 'a': 2}
Maybe I'm overthinking this and you just want:
sorted(d.values())
# [0, 1, 2]

Adding the values in a two different dictionaries and creating a new dictionary

I have the following two dictionaries
scores1={'a':10,'b':20,'c':30,'d':10} #dictionary holds value scores for a,b,c,d
and
scores2={'a':20,'b':10} #this dictionary only has scores for keys a and b
I need to collate and sum the scores for keys a and b in both dictionaries to produce the following output:
The answer could be 'done' using one of the following two methods (and there may be others I'd be interested to hear)
1. Using the creation of a new dictionary:
finalscores={a:30,b:30} #adds up the scores for keys a and b and makes a new dictionary
OR
2. update the scores2 dictionary (and add the values from scores1 to the scores2 corresponding respective values
An accepted answer would show both the above with any suitable explanation as well as suggest any more astute or efficient ways of solving the problem.
There was a suggestion on another SO answer that the dictionaries could simply be added:
print(scores1+scores2)
Is there any pythonic way to combine two dicts (adding values for keys that appear in both)?
But I want to do this in the simplest method possible, without iterator imports or classes
I have also tried, but to no avail:
newdict={}
newdict.update(scores1)
newdict.update(scores2)
for i in scores1.keys():
try:
addition = scores[i] + scores[i]
newdict[i] = addition
except KeyError:
continue
For the first solution:
scores1={'a':10,'b':20,'c':30,'d':10} #dictionary holds value scores for a,b,c,d
scores2={'a':20,'b':10} #this dictionary only has scores for keys a and b
finalscores=dict((key, sum([scores1[key] if key in scores1 else 0, scores2[key] if key in scores2 else 0])) for key in set(scores1.keys()+scores2.keys()))
print(finalscores)
# outputs {'a': 30, 'c': 30, 'b': 30, 'd': 10}
This iterates through a set of all keys in both dictionaries, creates a tuple with the values of the key in both dictionaries or 0 and then passes said tuple through the sum function adding the results. Finally, it generates a dictionary.
EDIT
In multiple lines, to understand the logic, this is what the one-liner does:
finalscores = {}
for key in set(scores1.keys()+scores2.keys()):
score_sum = 0
if key in scores1:
score_sum += scores1[key]
if key in scores2:
score_sum += scores2[key]
finalscores[key] = score_sum
For the second solution:
scores1={'a':10,'b':20,'c':30,'d':10} #dictionary holds value scores for a,b,c,d
scores2={'a':20,'b':10} #this dictionary only has scores for keys a and b
for k1 in scores1:
if k1 in scores2:
scores2[k1] += scores1[k1] # Adds scores1[k1] to scores2[k1], equivalent to do scores2[k1] = scores2[k1] + scores1[k1]
else:
scores2[k1] = scores1[k1]
print(scores2)
# outputs {'a': 30, 'c': 30, 'b': 30, 'd': 10}

dictionary with tuple as key

Currently I created a dictionary that uses tuple pairs as keys. My dictionary currently counts pairs such as (a,b) and (b,a) separately, but I ultimately want (a,b) == (b,a).
Currently that portion of my code looks like this:
final = collections.defaultdict(list)
for a,b in pairs:
final[(a[0],b[0])].append((a[2],a[1]))
final[(b[0],a[0])].append((b[2],b[1]))
Would I have to check if the (b,a) of the (a,b) already exists in the dictionary prior to adding it? Or do I fix the dictionary after it's all completed?
Use frozenset([a, b]). Sets compare equal regardless of order, but only frozensets can be used as dictionary keys because they're immutable.
If a == b though your key will be equal to frozenset([a]). If this is a problem, we can make a plan.
pairs = [frozenset([1,2]), frozenset([3,4]), frozenset([2,1]),
frozenset([5,6]), frozenset([7,8]), frozenset([6,5])]
for pair in pairs:
pair_count.update({pair: pair_count.get(pair, 0) + 1})
pair_count
{frozenset([5, 6]): 2, frozenset([1, 2]): 2, frozenset([8, 7]): 1, frozenset([3, 4]): 1}

Sorting with a python dictionary

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

How to reorder a python ordered dict based on array?

Say I have an Ordered Dict with the following items:
mydict = {'Rust': {'definition':'rusts definition'}, 'Iron': {'definition:'iron definition'}, 'Pyrite': {'definition':'pyrite definition'}}
If I have an array:
myorder = ['Pyrite', 'Rust', 'Iron']
How can I reorder the Ordered Dict such that the items in mydict are ordered based on myorder?
Try this:
mydict = {'Rust': {'definition':'rusts definition'},
'Iron': {'definition':'iron definition'},
'Pyrite': {'definition':'pyrite definition'}}
myorder = ['Pyrite', 'Rust', 'Iron']
from collections import OrderedDict
ordered = OrderedDict()
for k in myorder:
ordered[k] = mydict[k]
Or even shorter:
ordered = OrderedDict((k, mydict[k]) for k in myorder)
Using the above snippet, ordered will contain the same keys/values as mydict, but they'll be inserted in the same order specified by myorder. That's the advantage of OrderedDict: when iterating over it, it'll preserve the insertion order.
There's no way to sort the existing dictionary in-place (well, you could extract all the key-value pairs, eliminate them and add them again in the correct order, but that's not the idea, is it?), it's necessary to create a new one ... or simply iterate over the existing dictionary in the specified order:
for k in myorder:
x = mydict[k] # do something with x
If you would like to use them in that order, you can do this, for example.
for key in myorder:
value = mydict[key]
print value
Outputs:
{'definition': 'pyrite definition'}
{'definition': 'rusts definition'}
{'definition': 'iron definiti

Categories

Resources