How to update list recursively - python

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}]

Related

Sort dictionary with attribute value

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

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])

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

Modifying list of dictionary using list comprehension

So I have the following list of dictionary
myList = [{'one':1, 'two':2,'three':3},
{'one':4, 'two':5,'three':6},
{'one':7, 'two':8,'three':9}]
This is just an example of a dictionary that I have. My question is, it possible to somehow modify say key two in all the dictionary to become twice their value, using list comprehension ?
I know how to use list comprehension to create new list of dictionary, but don't know how to modify them, I have come up with something like this
new_list = { <some if condiftion> for (k,v) in x.iteritems() for x in myList }
I am not sure how to specify a condition in the <some if condiftion>, also is the nested list comprehension format I am thinking of correct ?
I want the final output as per my example like this
[ {'one':1, 'two':4,'three':3},{'one':4, 'two':10,'three':6},{'one':7, 'two':16,'three':9} ]
Use list comprehension with nested dict comprehension:
new_list = [{ k: v * 2 if k == 'two' else v for k,v in x.items()} for x in myList]
print (new_list)
[{'one': 1, 'two': 4, 'three': 3},
{'one': 4, 'two': 10, 'three': 6},
{'one': 7, 'two': 16, 'three': 9}]
In python 3.5+ you can use the new unpacking syntax in dict literals introduced in PEP 448. This creates a copy of each dict and then overwrites the value for the key two:
new_list = [{**d, 'two': d['two']*2} for d in myList]
# result:
# [{'one': 1, 'two': 4, 'three': 3},
# {'one': 4, 'two': 10, 'three': 6},
# {'one': 7, 'two': 16, 'three': 9}]
myList = [ {'one':1, 'two':2,'three':3},{'one':4, 'two':5,'three':6},{'one':7, 'two':8,'three':9} ]
[ { k: 2*i[k] if k == 'two' else i[k] for k in i } for i in myList ]
[{'one': 1, 'three': 3, 'two': 4}, {'one': 4, 'three': 6, 'two': 10}, {'one': 7, 'three': 9, 'two': 16}]
A simple for loop should be sufficient. However, if you want to use a dictionary comprehension, I find defining a mapping dictionary more readable and extendable than ternary statements:
factor = {'two': 2}
res = [{k: v*factor.get(k, 1) for k, v in d.items()} for d in myList]
print(res)
[{'one': 1, 'two': 4, 'three': 3},
{'one': 4, 'two': 10, 'three': 6},
{'one': 7, 'two': 16, 'three': 9}]
Hello did you tried this :
for d in myList:
d.update((k, v*2) for k, v in d.iteritems() if k == "two")
Thanks

How to convert list of dictionaries to dictionaries

mylist = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}]
i want it as
myDict ={'a': 1, 'b': 2,'c': 3, 'd': 4,'e': 5, 'f': 6}
You can make use of ChainMap.
from collections import ChainMap
myDict = dict(ChainMap(*mylist ))
This will take each dictionary and iterate through its key value pairs in for (k,v) in elem.items() part and assign them to a new dictionary.
mylist = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}]
new_dict = {k:v for elem in mylist for (k,v) in elem.items()}
print new_dict
This will replace the duplicated keys.
I would create a new dictionary, iterate over the dictionaries in mylist, then iterate over the key/value pairs in that dictionary. From there, you can add each key/value pair to myDict.
mylist = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}]
myDict = {}
for Dict in mylist:
for key in Dict:
myDict[key] = Dict[key]
print(myDict)

Categories