append values to a dict in python - python

I have a list of dictionaries -
list1 = [{'id' : '1', 'b' : '2', 'c' : '3'}, {'id' : '4', 'b' : '5', 'c' : '6'}, {'id' : '7', 'b' : '8', 'c' : ''}]
Based on the value of c being null or not, I am making a call which returns -
list2 - {'d' : '30', 'id' : 1}, {'d': '25', 'id' : '4'}
Now I want to modify list1, so that the final list has the values of d for the ids which have c. For example -
list1 = [{'id' : '1', 'b' : '2', 'c' : '3', 'd' : '30'}, {'id' : '4', 'b' : '5', 'c' : '6', 'd' : '25'}, {'id' : '7', 'b' : '8', 'c' : ''}]
My approach -
for l in list2:
current_list = {}
for l2 in list1:
if l2['id'] == l['id']:
current_list = l2
break
if current_list:
current_list['d'] = l['d']
Here the actual dict is not getting modified. How can I modify the actual list? Also, is there a neater way to do this?

I'm not certain I understand what you are trying to accomplish. Your written description of your goal does not agree with you code. Based on the code, I'm guessing that you want to match up the data based on the id values.
# You've got some dicts.
dicts = [
{'id': '1', 'b': '2', 'c': '3'},
{'id': '4', 'b': '5', 'c': '6'},
{'id': '7', 'b': '8', 'c': ''},
]
# You've got some other dicts having the same IDs.
d_dicts = [
{'d': '30', 'id': '1'},
{'d': '25', 'id': '4'},
]
# Reorganize that data into a dict, keyed by ID.
dlookup = {d['id'] : d['d'] for d in d_dicts}
# Now add that lookup data to the main list of dicts.
for d in dicts:
i = d['id']
if i in dlookup:
d['d'] = dlookup[i]

Assuming mr FMc are correct, there is in python 3.5 a valid approach to merge dicts. Which in this case would led us to:
dicts = [
{'id': '1', 'b': '2', 'c': '3'},
{'id': '4', 'b': '5', 'c': '6'},
{'id': '7', 'b': '8', 'c': ''},
]
d_dicts = [
{'d': '30', 'id': '1'},
{'d': '25', 'id': '4'},
]
dicts = [{**d, **dict(*filter(lambda x: x["id"] == d["id"], d_dicts))} for d in dicts]
I like these kinda expressions instead of writing it all out, but it has the "benefit" of crashing instead of overwriting stuff when there is more then one dict with the same id. But my solution still overwrites values if there are duplicate keys silently. The inserted value being the value from whatever's second in the dict merge.

Related

dict from a dict of list

I have a Python dictionary with following format:
d1 = {'Name':['ABC'], 'Number':['123'], 'Element 1':['1', '2', '3'],
'Element2':['1','2','3']}
Expected output:
{'Name': 'ABC', 'Number': '123',
'Elements': [{'Element 1': '1', 'Element2': '1'},
{'Element 1': '2', 'Element2': '2'},
{'Element 1': '3', 'Element2': '3'}]
I have tried the following:
[{k: v[i] for k, v in d1.items() if i < len(v)}
for i in range(max([len(l) for l in d1.values()]))]
but getting this result:
[{'Name': 'ABC', 'Number': '123', 'Element 1': '1', 'Element 2': '1'},
{'Element 1': '2', 'Element 2': '2'},
{'Element 1': '3', 'Element 2': '3'}]
How can I go from here?
I strongly recommend not trying to do everything in one line. It's not always more efficient, and almost always less readable if you have any branching logic or nested loops.
Given your dict, we can pop() the Name and Number keys into our new dict. Then
output = dict()
d1 = {'Name':['ABC'], 'Number':['123'], 'Element 1':['1', '2', '3'], 'Element2':['1','2','3']}
output["Name"] = d1.pop("Name")
output["Number"] = d1.pop("Number")
print(output)
# prints:
# {'Name': ['ABC'], 'Number': ['123']}
print(d1)
# prints:
# {'Element 1': ['1', '2', '3'], 'Element2': ['1', '2', '3']}
Then, we zip all remaining values in the dictionary, and add them to a new list:
mylist = []
keys = d1.keys()
for vals in zip(*d1.values()):
temp_obj = dict(zip(keys, vals))
mylist.append(temp_obj)
print(mylist)
# prints:
# [{'Element 1': '1', 'Element2': '1'},
# {'Element 1': '2', 'Element2': '2'},
# {'Element 1': '3', 'Element2': '3'}]
And finally, assign that to output["Elements"]
output["Elements"] = mylist
print(output)
# prints:
# {'Name': ['ABC'], 'Number': ['123'], 'Elements': [{'Element 1': '1', 'Element2': '1'}, {'Element 1': '2', 'Element2': '2'}, {'Element 1': '3', 'Element2': '3'}]}
Since you don't want to hardcode the first two keys,
for k, v in d1.items():
if "element" not in k.lower():
output[k] = v
Or as a dict-comprehension:
output = {k: v for k, v in d1.items() if "element" not in k.lower()}
use a list of tuples to create the elements list of dictionaries. Use Convert to build your dictionary item from the tuple.
#https://www.geeksforgeeks.org/python-convert-list-tuples-dictionary/
d1 = {'Name':['ABC'], 'Number':['123'], 'Element 1':['1', '2', '3'],
'Element2':['1','2','3']}
def Convert(tup, di):
for a, b in tup:
di[a]=b
return di
dict={}
listElements=[]
for key,value in d1.items():
if isinstance(value,list) and len(value)>1:
for item in value:
listElements.append((key,item))
elif isinstance(value,list) and len(value)==1:
dict[key]=value[0]
else:
dict[key]=value
dict['Elements']=[Convert([(x,y)],{}) for x,y in listElements]
print(dict)
output:
{'Name': 'ABC', 'Number': '123', 'Elements': [{'Element 1': '1'}, {'Element 1': '2'}, {'Element 1': '3'}, {'Element2': '1'}, {'Element2': '2'}, {'Element2': '3'}]}
I'm going to explain step by step:
We build new_d1 variable, that is the dictionary you expect as output and it's initialized as {'Name': 'ABC', 'Number': '123'}. For achieving the above, we use comprehension notation taking into account the keys != 'Element'
new_d1 = {key: d1.get(key)[0] for key in filter(lambda x: 'Element' not in x, d1)}
We build elements variable, that's a list with the dictionaries matter for us, I mean, the dictionaries we have to manipulate to achieve the expected result. Then elements is [{'Element 1': ['1', '2', '3']}, {'Element2': ['1', '2', '3']}].
elements = [{key: d1.get(key)} for key in filter(lambda x: 'Element' in x, d1)]
We are going to do a Cartesian product using itertools.product taking into account each key and each item of the values present in elements.
product = [list(it.product(d.keys(), *d.values())) for d in elements]
Using zip, we arrange the data and covert them in dictionary. And finally we create "Elements" key in new_df1
elements_list = [dict(t) for index, t in enumerate(list(zip(*product)))]
new_d1["Elements"] = elements_list
print(new_d1)
Full code:
import itertools as it
new_d1 = {key: d1.get(key)[0] for key in filter(lambda x: 'Element' not in x, d1)}
elements = [{key: d1.get(key)} for key in filter(lambda x: 'Element' in x, d1)]
product = [list(it.product(d.keys(), *d.values())) for d in elements]
elements_list = [dict(t) for index, t in enumerate(list(zip(*product)))]
new_d1["Elements"] = elements_list
Output:
{'Elements': [{'Element 1': '1', 'Element2': '1'},
{'Element 1': '2', 'Element2': '2'},
{'Element 1': '3', 'Element2': '3'}],
'Name': 'ABC',
'Number': '123'}

How to merge dict of dict in python

Two dictionary is below
d1 = {'1': {'index': '1', 'sc': '4', 'st': '3'}, '2': {'index': '2', 'sc': '5', 'st': '5'}}
d2 = {'1': {'diff': 1}, '2': {'diff': 0}}
Code is below
z = {**d2, **d1} why this is not working
Tried below code also
def Merge(d1, d2):
return(d2.update(d1))
print(Merge(d1, d2))
Expetec out below
{'1': {'index': '1', 'sc': '4', 'st': '3', 'diff': 1},
'2': {'index': '2', 'sc': '5', 'st': '5', 'diff': 0}}
an alternate way using pandas
>>> import pandas as pd
>>> df = pd.DataFrame(d1)
>>> df2 = pd.DataFrame(d2)
>>> merged_dict = pd.concat([df,df2]).to_dict()
output
>>> merged_dict
{'1': {'index': '1', 'sc': '4', 'st': '3', 'diff': 1}, '2': {'index': '2', 'sc': '5', 'st': '5', 'diff': 0}}
generally, ** will capture any keyword arguments we pass to the function into a dictionary which that attributes arguments will reference. For example:
d1={'a':1,'b':2}
d2={'c':3,'d':4}
def merge(**di):
res = {}
for k, v in di.items():
try:
res[k].append(v)
except KeyError:
res[k] = [v]
return res
print(merge(**d1, **d2))
# {'a': [1], 'b': [2], 'c': [3], 'd': [4]}
However, if we pass in two dictionary with same keys:
d1 = {'1': {'index': '1', 'sc': '4', 'st': '3'}, '2': {'index': '2', 'sc': '5', 'st': '5'}}
d2 = {'1': {'diff': 1}, '2': {'diff': 0}}
def merge(**di):
res = {}
for k, v in di.items():
try:
res[k].append(v)
except KeyError:
res[k] = [v]
return res
print(merge(**d1, **d2))
# TypeError: merge() got multiple values for keyword argument '1'
This error is handled by continuing which keep the original one and skip the second dict key. Sorry I don't have a shorthand method for this.
d1 = {'1': {'index': '1', 'sc': '4', 'st': '3'}, '2': {'index': '2', 'sc': '5', 'st': '5'}}
d2 = {'1': {'diff': 1}, '2': {'diff': 0}}
def merge(*args):
res = {}
for di in args:
for k, v in di.items():
try:
res[k].update(v)
except KeyError:
res[k] = v
return res
print(merge(d1, d2))
# {'1': {'index': '1', 'sc': '4', 'st': '3', 'diff': 1}, '2': {'index': '2', 'sc': '5', 'st': '5', 'diff': 0}}
z = {**d2, **d1}
Overwrites everything in d2 with d1 values for keys '1', and '2'. It is tricky to merge dictionaries with the same keys so you don't overwrite key:value pairs within those keys.
The following will get you to the depth needed in both d1 and d2 to update d1 to your expected output:
d1['1']['diff'] = d2['1']['diff']
d1['2']['diff'] = d2['2']['diff']
print ('d1:', d1)
Output:
d1: {'1': {'index': '1', 'sc': '4', 'st': '3', 'diff': 1}, '2': {'index': '2', 'sc': '5', 'st': '5', 'diff': 0}}
>>> for key in d1:
... d1[key].update(d2[key])
>>> d1
{'1': {'index': '1', 'sc': '4', 'st': '3', 'diff': 1}, '2': {'index': '2', 'sc': '5', 'st': '5', 'diff': 0}}
Update:
If you want in another identifier d3.
d3 = d1.copy()
for key in d3:
d3[key].update(d2[key])
print(d3)
Dictionaries are mutable objects. update function just mutates/updates the object and return None. So, you need to create a copy (so you have another object) and change the new object, if you want initial data unaltered.

Appending list of dicts with dicts from list (circular?)

I'm trying to loop through a list of dictionaries and search for a specific key. If the value of that key matches a specific value, another list of dictionaries is provided. I would like to append the original list of dictionaries with the new dictionaries.
def test():
info = [{'a': '1', 'b': '2'}, {'a': '3', 'b': '4'}]
for item in info:
if "1" in item['a']:
info2 = [{'c': '1', 'd': '2'}, {'c': '3', 'd': '4'}]
for dict in info2:
info.append(dict)
I was hoping my above attempt would result in the original info list being as follows:
info = [{'a': '1', 'b': '2'}, {'a': '3', 'b': '4'}, {'c': '1', 'd': '2'}, {'c': '3', 'd': '4'}]
however I just end up with TypeErrors:
TypeError: string indices must be integers.
Thanks in advance for any assistance
Some issues in your code
You are trying to modify the info list you are iterating on, instead you should iterate on the copy of info via for item in info[:]:
You can change item['a'] to item.get('a') to make sure getting item doesn't thwo an exception if the key is not present, and you can change in to equality
You can add the dictionaries from info2 list to info list by extend the list using list.extend
Then your updated code will be
def test():
info = [{'a': '1', 'b': '2'}, {'a': '3', 'b': '4'}]
#Iterate on copy of info
for item in info[:]:
#If value of a equals 1
if item.get('a') == '1':
#Extend the original list
info2 = [{'c': '1', 'd': '2'}, {'c': '3', 'd': '4'}]
info.extend(info2)
return info
print(test())
And the output will be
[
{'a': '1', 'b': '2'},
{'a': '3', 'b': '4'},
{'c': '1', 'd': '2'},
{'c': '3', 'd': '4'}
]

Making a dictionary where key is a list [duplicate]

This question already has answers here:
List of dicts to/from dict of lists
(14 answers)
Closed 4 years ago.
so given a list of dictionaries:
my_dict= [{'a': '4', 'b': '5', 'c': '1', 'd': '3'},
{'a': '1', 'b': '8', 'c': '1', 'd': '2'},
{'a': '7', 'b': '4', 'c': '1', 'd': '5'}]
and a list of keys in the dictionary for example [ 'a', 'b']
I am trying to make a list of dictionaries for both 'a' and 'b' for their respective values i.e the final product will resemble
new_dict = ['a':['4', '1', '7'], 'b':['5', '8', '4']]
any help will be appreciated
Using collections
Demo:
import collections
d = collections.defaultdict(list)
my_dict= [{'a': '4', 'b': '5', 'c': '1', 'd': '3'}, {'a': '1', 'b': '8', 'c': '1', 'd': '2'}, {'a': '7', 'b': '4', 'c': '1', 'd': '5'}]
for i in my_dict:
for k,v in i.items():
d[k].append(v)
print( d )
Output:
defaultdict(<type 'list'>, {'a': ['4', '1', '7'], 'c': ['1', '1', '1'], 'b': ['5', '8', '4'], 'd': ['3', '2', '5']})

Python add sequential value array to dict

For example i have dict python
dict = {'a': '1', 'b': '2', 'c': '3'}
and array
arr = ['4', '5', '6']
I want add sequential value array to dict
dict1 = {'a': '4', 'b': '5', 'c': '6'}
Please suggest a specific solution.
>>> d = {'a': '1', 'b': '2', 'c': '3'}
>>> arr = ['4', '5', '6']
>>> dict(zip(sorted(d), arr))
{'a': '4', 'c': '6', 'b': '5'}
You can use zip:
>>> import string
>>> arr = ['4', '5', '6']
>>> # dict(zip(sorted(original_dict), arr))
>>> dict(zip(string.ascii_lowercase, arr))
{'b': '5', 'c': '6', 'a': '4'}
BTW, don't name a varialbe dict. It will shadows builtin type/function dict.
Not sure what you are trying to do, but the below code snippet does what you intend in your question.
import os
dict = {'a': '1', 'b': '2', 'c': '3'}
arr = ['4', '5', '6']
dict1 = {}
dictAsList = dict.items()
i = 0
for key in sorted(dict):
try:
dict1[key] = arr[i]
except:
pass
i = i+1
print dict1
Python dictionary doesn't have order. So I don't get what sequential means in dictionary.
If you just want to set all value to another value you can do like this.
d = {'a': '1', 'b': '2', 'c': '3'}
arr = ['4', '5', '6']
print dict(zip(d.keys(), arr))
#{'a': '4', 'c': '5', 'b': '6'}
If you want to set value as same order you can do like this.(You need change your data structure)
from collections import OrderedDict
d = OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])
arr = ['4', '5', '6']
print dict(zip(d.keys(), arr))
#{'a': '4', 'c': '6', 'b': '5'}

Categories

Resources