Sort dictionary with attribute value - python

I have a list dictionary like this: {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}} and want to sort it using its score attribute.
Intended output: {2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}, 1: {'a': 5, 'score': 3}}
I have trying to use the built-in function to sort the list but its not giving desired output
updatedList = sorted(b, key=lambda k: k['score'])
Any hints how I can get the desired output?

Your data structure is a nested dictionary, not a list.
To sort the dictionary, you can modify your key function to this:
>>> d = {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}}
>>> dict(sorted(d.items(), key=lambda x: x[1]['score']))
{2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}, 1: {'a': 5, 'score': 3}}
Which converts the original dictionary to dict.items, then uses the score key from the dictionary in the (key, value) tuple. Then after sorting with sorted(), we can convert back to a dictionary with dict().
This works in Python 3.6+ since dictionaries are ordered. If you are using a lower python version, you can maintain dictionary insertion order with collections.OrderedDict instead.

For sorting a Nested Dictionary use the key argument for sorted(). It lets you specify a function that, given the actual item being sorted, returns a value that should be sorted by.
N_Dictionary = {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}}
s_values = sorted(N_Dictionary.items(), key = lambda x: x[1]["score"] )
s_values

Related

Multiple similar values of a dictionary in an array changes when one of the values is modified

Let's say I'm performing some operation on an array as follows:
>>arr = np.array([1,2,34,567,433243,787,832])
>>h = np.where(arr < 100, {'hello' : 1}, {'hi' : 2 })
array([{'hello': 1}, {'hello': 1}, {'hello': 1}, {'hi': 2}, {'hi': 2},{'hi': 2}, {'hi': 2}], dtype=object)
When I try to add a key-value pair at some selective indices, It gets replicated across all the indices and gives me something like this:
>>h[0]['hola']=12
>>h[4]['heyy']=11
>>h
array([{'hello': 1, 'hola': 12}, {'hello': 1, 'hola': 12},{'hello': 1, 'hola': 12}, {'hi': 2, 'heyy': 11},{'hi': 2, 'heyy': 11}, {'hi': 2, 'heyy': 11},{'hi': 2, 'heyy': 11}], dtype=object)
While I expect the values to change only at those specific indices(0 & 4) and get something like this:
array([{'hello': 1, 'hola': 12}, {'hello': 1}, {'hello': 1}, {'hi': 2}, {'hi': 2, 'heyy': 11}, {'hi': 2,}, {'hi': 2}], dtype=object)
How do I obtain the desired output?.Thanks in advance
you are passing 3 args to np.where a condition an expression if its true and and expression if its false. These expressions are evaluated before being passed to the where method. Such that the dicts are created once for true and once for false then the same dict will be used whenever that Boolean value occurs in the expression.
Instaed you can just use a list comprehension to achieve what you want.
h = np.array([{'hello': 1} if i < 100 else {'hi': 2} for i in arr])

How to update list recursively

I have a list of dicts:
a = [{'one': 1}, {'two': 2}, {'three': 3}, {'four': 4}, {'five': 5}]
I want to update the value of each element in this list by the sum of all remainders. (so 'one' will get the value 2+3+4+5) .
so that it will look like this:
a = [{'one': 14}, {'two': 12}, {'three': 9}, {'four': 5}, {'five': 5}]
'five' is the last, so it will not update .
Im not sure how to achieve this. Im thinking that you construct a function that will call itself recursivly something like:
def recursive(a):
if len(a) == 1:
return list(a[0].values())[0]
else:
val = list(a[0].values())[0]
return val + recursive(a.pop(0))
But Im not sure to do this list(a[0].values())[0] is the "best" way. And this is also getting a KeyError: 0.
Any ideas?
Iterative and in place solution
a = [{'one': 1}, {'two': 2}, {'three': 3}, {'four': 4}, {'five': 5}]
sum_so_far = 0
first_flag = False
for i in a[::-1]:
k,v = i.items()[0] #For Python 3 k,v = list(i.items())[0]
sum_so_far += v
if first_flag:
i[k] = sum_so_far # do not change the value at first
first_flag=True
Output
[{'one': 15}, {'two': 14}, {'three': 12}, {'four': 9}, {'five': 5}]
Your problem comes from the output of a.pop(0). A.pop(0) returns the element at 0, not the list without the element at 0. Therefore, when you call recursively, you are indexing on a dict, rather than a list. What do you expect to be inputting into the recursive call?
I would guess you are trying to remove the 0th index, then call recursively. To do this,
a.pop(0);
return val + recursive(a)
edit: a note - key error 0 means you are indexing a dict with key 0 when key 0 does not yet exist.
A possible recursive solution:
d = [{'one': 1}, {'two': 2}, {'three': 3}, {'four': 4}, {'five': 5}]
def sums(data, _sum = 0):
a, *b = data
if not b:
return [a], list(a.values())[0]
c, _d = sums(b, _sum+list(a.values())[0])
return [{list(a.keys())[0]:_d}, *c], _d+list(a.values())[0]
result, _ = sums(d)
Output:
[{'one': 14}, {'two': 12}, {'three': 9}, {'four': 5}, {'five': 5}]
Quick and dirty one liner...
[{list(d.keys())[0]: sum(list(v.values())[0] for v in a[i + (1 if i<len(a)-1 else 0):])} for i, d in enumerate(a)]
# [{'one': 14}, {'two': 12}, {'three': 9}, {'four': 5}, {'five': 5}]

Remove duplicate dictionaries from a list and subtract value of keys of duplicate element

I have a list of dicts, and I'd like to remove the dicts with identical key and subtract the value pairs.
For this list:
[{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
I'd like to return this:
[{'chair': 1}, {'tv': 3}, {'laptop': 2}]
You could do it like this, creating an intermediate dict for efficiency:
dicts_list = [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
out = {}
for d in dicts_list:
for key, val in d.items():
if key in out:
out[key] -= val
else:
out[key] = val
out_list = [ {key:val} for key, val in out.items()]
print(out_list)
# [{'tv': 3}, {'chair': 1}, {'laptop': 2}]
But you might be interested in this intermediate dict as output:
print(out)
# {'tv': 3, 'chair': 1, 'laptop': 2}
defaultdict from collections might come in handy. This solution will cover the cases where there are more than 2 dicts of the same key in the list.
from collections import defaultdict
ls = defaultdict(list)
d = [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
# Creating a list of all values under one key
for dic in d:
for k in dic:
ls[k].append(dic[k])
print(ls)
defaultdict(<class 'list'>, {'chair': [4, 3], 'tv': [5, 2], 'laptop': [2]})
# safe proofing for negative values on subtraction
for k in ls:
ls[k].sort(reverse=True)
ls[k] = ls[k][0] - sum(ls[k][1:])
print(ls)
defaultdict(<class 'list'>, {'chair': 1, 'tv': 3, 'laptop': 2})
You can construct a defaultdict of lists, then use a list comprehension:
from collections import defaultdict
dd = defaultdict(list)
for d in data:
k, v = next(iter(d.items()))
dd[k].append(v)
res = [{k: v if len(v) == 1 else v[0] - sum(v[1:])} for k, v in dd.items()]
print(res)
# [{'chair': 1}, {'tv': 3}, {'laptop': [2]}]
Following snippet is using nothing but standard modules:
a= [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
print("Input:", a)
b=dict()
for element in a:
for k,v in element.items():
try:
# you didn't specify the subtracted element order,
# so I'm subtracting BIGGER from SMALLER using simple abs() :)
b[k] = abs(b[k] - v)
except:
b[k] = v
print("Output:", b)
# restore original structure
c = [ dict({item}) for item in b.items() ]
print("Output:", c)
And demo:
('Input:', [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}])
('Output:', {'tv': 3, 'chair': 1, 'laptop': 2})
('Output:', [{'tv': 3}, {'chair': 1}, {'laptop': 2}])
EDIT: Added the secondary out put C to restructure B similar to A

Convert pandas dataframe to dictionary with nested dictionary based on 2 key columns and 1 value column

I have a dataframe in pandas as follows:
df = pd.DataFrame({'key1': ['abcd', 'defg', 'hijk', 'abcd'],
'key2': ['zxy', 'uvq', 'pqr', 'lkj'],
'value': [1, 2, 4, 5]})
I am trying to create a dictionary with a key of key1 and a nested dictionary of key2 and value. I have tried the following:
dct = df.groupby('key1')[['key2', 'value']].apply(lambda x: x.set_index('key2').to_dict(orient='index')).to_dict()
dct
{'abcd': {'zxy': {'value': 1}, 'lkj': {'value': 5}},
'defg': {'uvq': {'value': 2}},
'hijk': {'pqr': {'value': 4}}}
Desired output:
{'abcd': {'zxy': 1, 'lkj': 5}, 'defg': {'uvq': 2}, 'hijk': {'pqr': 4}}
Using collections.defaultdict, you can construct a defaultdict of dict objects and add elements while iterating your dataframe:
from collections import defaultdict
d = defaultdict(dict)
for row in df.itertuples(index=False):
d[row.key1][row.key2] = row.value
print(d)
defaultdict(dict,
{'abcd': {'lkj': 5, 'zxy': 1},
'defg': {'uvq': 2},
'hijk': {'pqr': 4}})
As defaultdict is a subclass of dict, this should require no further work.

python: Convert a Counter object to a json object with added key names

I have a Counter object in Python, which contains the following data:
{'a': 4, 'b': 1, 'e': 1}
I'd like to convert this to a JSON object with the following form:
[{'name':'a', 'value': 4} , {'name':'b', 'value': 1}, {'name':'e', 'value': 1}]
Is there any efficient way to do so?
You can use a list comprehension to convert the dictionary to a list of dictionaries. Example -
data = {'a': 4, 'b': 1, 'e': 1}
result = [{'name':key, 'value':value} for key,value in data.items()]
Demo -
>>> data = {'a': 4, 'b': 1, 'e': 1}
>>> result = [{'name':key, 'value':value} for key,value in data.items()]
>>> result
[{'name': 'a', 'value': 4}, {'name': 'b', 'value': 1}, {'name': 'e', 'value': 1}]

Categories