Modifying list of dictionary using list comprehension - python

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

Related

Group all keys with the same value in a dictionary of sets

I am trying to transform a dictionary of sets as the values with duplication to a dictionary with the unique sets as the value and at the same time join the keys together.
dic = {'a': {1, 2, 3}, 'b': {1, 2}, 'c': {1, 3, 2}, 'd': {1, 2, 3}}
Should be changed to
{'a-c-d': {1, 2, 3}, 'b': {1, 2}}
My try is as below, but I think there has to be a better way.
def transform_dictionary(dic: dict) -> dict:
dic = {k: frozenset(v) for k, v in dic.items()}
key_list = list(dic.keys())
value_list = list(dic.values())
dict_transformed = {}
for v_uinque in set(value_list):
sub_key_list = []
for i, v in enumerate(value_list):
if v == v_uinque:
sub_key_list.append(str(key_list[i]))
dict_transformed['-'.join(sub_key_list)] = set(v_uinque)
return dict_transformed
print(transform_dictionary(dic))
You can "invert" the input dictionary into a dictionary mapping frozensets into a set of keys.
import collections
dic = {'a': {1, 2, 3}, 'b': {1, 2}, 'c': {1, 3, 2}, 'd': {1, 2, 3}}
keys_per_set = collections.defaultdict(list)
for key, value in dic.items():
keys_per_set[frozenset(value)].append(key)
Then invert that dictionary mapping back into the desired form:
{'-'.join(keys): value for (value, keys) in keys_per_set.items()}
Output:
{'a-c-d': frozenset({1, 2, 3}), 'b': frozenset({1, 2})}
This will turn the values into a frozenset, but you could "thaw" them with a set(value) in the last list comprehension.
from itertools import groupby
dic_output = {'-'.join(v):g for g,v in groupby(sorted(dic_input,
key=dic_input.get),
key=lambda x: dic_input[x])}
Output
{'b': {1, 2}, 'a-c-d': {1, 2, 3}}

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

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)

How to modify Python dictionary value and create the list of dictionaries?

I want to modify dictionary and to create a list that contains dictionaries with the modified values. I tried:
mylist = []
mydict = {"one": 10, "two": 20, "three": 30}
for i in [111, 222, 333]:
mydict["two"] = i
mylist.append(mydict)
mylist returns:
[{'three': 30, 'two': 333, 'one': 10}, {'three': 30, 'two': 333, 'one': 10}, {'three': 30, 'two': 333, 'one': 10}]
I expect to get:
[{'three': 30, 'two': 111, 'one': 10}, {'three': 30, 'two': 222, 'one': 10}, {'three': 30, 'two': 333, 'one': 10}]
How can I do it?
That's because you are just creating multiple references to same object (your dictionary) and by assigning the throwaway variable i to your keys which holds 333 at the last iteration and assign it to the two key, all of your dictionary names will point to same object with item ('two', 333).
You can use a dict comprehension for getting ride of this problem:
>>> mylist = [{"one": 10, "two": i, "three": 30} for i in [111, 222, 333]]
>>> mylist
[{'three': 30, 'two': 111, 'one': 10}, {'three': 30, 'two': 222, 'one': 10}, {'three': 30, 'two': 333, 'one': 10}]
Or you can create a copy of your initial object in each iteration in order to create a new object rather than just copying the references.
>>> from copy import copy
>>> mylist = []
>>> mydict = {"one": 10, "two": 20, "three": 30}
>>> for i in [111, 222, 333]:
... mydict["two"] = i
... mylist.append(copy(mydict))
...
>>> mylist
[{'one': 10, 'three': 30, 'two': 111}, {'one': 10, 'three': 30, 'two': 222}, {'one': 10, 'three': 30, 'two': 333}]
And if you have multiple keys that you want to modify, as a more pythonic approach you can do:
>>> for i, j in zip(my_keys, my_new_values):
... mydict[i] = j
... mylist.append(copy(mydict))

Split a dictionary in half?

What is the best way to split a dictionary in half?
d = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}
I'm looking to do this:
d1 = {'key1': 1, 'key2': 2, 'key3': 3}
d2 = {'key4': 4, 'key5': 5}
It does not matter which keys/values go into each dictionary. I am simply looking for the simplest way to divide a dictionary into two.
This would work, although I didn't test edge-cases:
>>> d = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}
>>> d1 = dict(d.items()[len(d)/2:])
>>> d2 = dict(d.items()[:len(d)/2])
>>> print d1
{'key1': 1, 'key5': 5, 'key4': 4}
>>> print d2
{'key3': 3, 'key2': 2}
In python3:
d = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}
d1 = dict(list(d.items())[len(d)//2:])
d2 = dict(list(d.items())[:len(d)//2])
Also note that order of items is not guaranteed
Here's a way to do it using an iterator over the items in the dictionary and itertools.islice:
import itertools
def splitDict(d):
n = len(d) // 2 # length of smaller half
i = iter(d.items()) # alternatively, i = d.iteritems() works in Python 2
d1 = dict(itertools.islice(i, n)) # grab first n items
d2 = dict(i) # grab the rest
return d1, d2
d1 = {key: value for i, (key, value) in enumerate(d.viewitems()) if i % 2 == 0}
d2 = {key: value for i, (key, value) in enumerate(d.viewitems()) if i % 2 == 1}
If you use python +3.3, and want your splitted dictionaries to be the same across different python invocations, do not use .items, since the hash-values of the keys, which determines the order of .items() will change between python invocations.
See Hash randomization
The answer by jone did not work for me. I had to cast to a list before I could index the result of the .items() call. (I am running Python 3.6 in the example)
d = {'one':1, 'two':2, 'three':3, 'four':4, 'five':5}
split_idx = 3
d1 = dict(list(d.items())[:split_idx])
d2 = dict(list(d.items())[split_idx:])
"""
output:
d1
{'one': 1, 'three': 3, 'two': 2}
d2
{'five': 5, 'four': 4}
"""
Note the dicts are not necessarily stored in the order of creation so the indexes may be mixed up.
Here is the function which can be used to split a dictionary to any divisions.
import math
def linch_dict_divider(raw_dict, num):
list_result = []
len_raw_dict = len(raw_dict)
if len_raw_dict > num:
base_num = len_raw_dict / num
addr_num = len_raw_dict % num
for i in range(num):
this_dict = dict()
keys = list()
if addr_num > 0:
keys = raw_dict.keys()[:base_num + 1]
addr_num -= 1
else:
keys = raw_dict.keys()[:base_num]
for key in keys:
this_dict[key] = raw_dict[key]
del raw_dict[key]
list_result.append(this_dict)
else:
for d in raw_dict:
this_dict = dict()
this_dict[d] = raw_dict[d]
list_result.append(this_dict)
return list_result
myDict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}
print myDict
myList = linch_dict_divider(myDict, 2)
print myList
We can do this efficiently with itertools.zip_longest() (note this is itertools.izip_longest() in 2.x):
from itertools import zip_longest
d = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}
items1, items2 = zip(*zip_longest(*[iter(d.items())]*2))
d1 = dict(item for item in items1 if item is not None)
d2 = dict(item for item in items2 if item is not None)
Which gives us:
>>> d1
{'key3': 3, 'key1': 1, 'key4': 4}
>>> d2
{'key2': 2, 'key5': 5}
Here's a function that I use in Python 3.8 that can split a dict into a list containing the desired number of parts. If you specify more parts than elements, you'll get some empty dicts in the resulting list.
def split_dict(input_dict: dict, num_parts: int) -> list:
list_len: int = len(input_dict)
return [dict(list(input_dict.items())[i * list_len // num_parts:(i + 1) * list_len // num_parts])
for i in range(num_parts)]
Output:
>>> d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
>>> split_dict(d, 2)
[{'a': 1, 'b': 2}, {'c': 3, 'd': 4, 'e': 5}]
>>> split_dict(d, 3)
[{'a': 1}, {'b': 2, 'c': 3}, {'d': 4, 'e': 5}]
>>> split_dict(d, 7)
[{}, {'a': 1}, {'b': 2}, {}, {'c': 3}, {'d': 4}, {'e': 5}]
If you used numpy, then you could do this :
def divide_dict(dictionary, chunk_size):
'''
Divide one dictionary into several dictionaries
Return a list, each item is a dictionary
'''
import numpy, collections
count_ar = numpy.linspace(0, len(dictionary), chunk_size+1, dtype= int)
group_lst = []
temp_dict = collections.defaultdict(lambda : None)
i = 1
for key, value in dictionary.items():
temp_dict[key] = value
if i in count_ar:
group_lst.append(temp_dict)
temp_dict = collections.defaultdict(lambda : None)
i += 1
return group_lst

Categories