Nested Dictionary Python:Update logic failing - python

My dictionary :
d={'a':'a1,a2,a3,a4','b':'b1,b2,b3,b4',c:'c1,c2,c3,c4'}
and so on d,e,f,....
d2={'a1':'a11,a12,a13,a14,a15','a2':'a21,a22,a23,a24,a25'}
and so on for a3,a4,a5,b1,b2....
Expected output
dict1={'a':{'a1':'a11,a12,a13,a14,a15','a2':'a21,a22,a23,a24,a25'}}
and so on for rest
My Output
dict1={'a':{'a1':'a11,a12,a13,a14,a15'},'a2':'a21,a22,a23,a24,a25'}
and so on then again
'b':{'b1':'b11,b12,b13,b14,b15'},'b2':'b21,b22,b23,b24,b25'}
My Code:
dict1={}
for i in d:
q=d[i].split(",")
for j in q:
dict1[i] = {}
if j in d2:
dict1[i][j] = d2[j]
dict1.update(dict1[i])
Any help would be very useful

You can try nested dictionary comprehension with list comprehension
d={'a':'a1,a2,a3,a4','b':'b1,b2,b3,b4','c':'c1,c2,c3,c4'}
d2={'a1':'a11,a12,a13,a14,a15','a2':'a21,a22,a23,a24,a25', 'b1':'b11,b12,b13,b14,b15','b2':'b21,b22,b23,b24,b25'}
dict1 = {k: {i: d2[i] for i in v.split(",") if i in d2} for k, v in d.items()})
print(dict1)
Output in this case
{'a': {'a1': 'a11,a12,a13,a14,a15', 'a2': 'a21,a22,a23,a24,a25'}, 'b': {'b1': 'b11,b12,b13,b14,b15', 'b2': 'b21,b22,b23,b24,b25'}, 'c': {}}
So if there will be values in d2 about the the c's they will be in the dict1 results as well.

Maybe you can try with:
dict1={}
for i in d:
q=d[i].split(",")
for j in q:
if not dict1.get(i, None):
dict1[i] = {}
if j in d2:
dict1[i][j] = d2[j]

Related

How to extract values from list of dictionary that match the keys in another list

I have a list of keys:
l_keys = ['a', 'c', 'd']
And I have a list of dictionary:
l_dict = [{'a': 1, 'b': 2, 'c': 3}, {'a':4, 'd':5}]
The result I want to get is:
[{'a': 1, 'c': 3}, {'a': 4, 'd': 5}]
.
I can achieve this result in the following way
[{k: d[key] for k in l_keys if k in l_dict} for d in l_dict]
.
Explain:
I actually go through every object in l_dict and then I go through every key in l_keys and check if that key is in the current object and if so I retrieve it and its value
My question is if there is a better, professional and faster way in terms of time complexity to do that.
Firstly, your list comprehension should be: [{k: d[k] for k in l_keys if k in d} for d in l_dict]
If you know that len(l_keys) will usually be smaller than the dicts in l_dict, your way is the most efficient. Otherwise, it would be better to check whether each key in the dict is in l_keys: [{k: d[k] for k in d if k in l_keys} for d in l_dict] l_set = set(l_keys): [{k: d[k] for k in d if k in l_set} for d in l_dict]
This page might be helpful when it comes to time complexity: https://wiki.python.org/moin/TimeComplexity#dict

How to extract the values from the dictionary with condition

My dictionary is below, if the values end with csv or json i need to put in another dictionary of same dictionary:
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
Code is below:
d = {}
for k,v in d.items():
for i in v:
if i.split('.')[1] == 'csv' or i.split('.')[1] == 'json':
d[k] = v
My out
{'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
Expected out
{'a': ['1.json', '1.csv'], 'B': ['2.json', '2.csv']}
You never change v, so the dictionary is unchanged. You should build a new list only keeping the wanted values:
for k,v in d.items():
v = [i for i in v if i.split('.')[1] in ('csv', 'json')]
d[k] = v
or even better:
d = {k: [i for i in v if i.split('.')[1] in ('csv', 'json')]
for k,v in d.items()}
You can try to use rfind to find the last . in the file name and to add it the list if it's matching CSV or JSON
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
for k, v in d.items():
d[k] = []
for i in v:
if i[i.rfind(".") + 1:] in ('csv', 'json'):
d[k].append(i)
Please test it:
from collections import defaultdict
x = defaultdict(list)
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
for k, v in d.items():
for i in v:
if i.split('.')[-1] in ['csv', 'json']:
x[k].append(i)
print(dict(x))
You can use dict comprehension with list comp on each of the values while filtering with str.endswith.
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
new = {k:[i for i in v if i.endswith(('.csv','.json'))] for k,v in d.items()}
# {'a': ['1.json', '1.csv'], 'B': ['2.json', '2.csv']}
A simple solution would be the following, assuming you want to update the existing dictionary
for k, v in d.items():
for i in v:
if i.rsplit('.')[-1] not in {'csv','json'}:
v.remove(i)
You can use split filename and add condition for checking the file type (using list for comparison could be a better option if you want to add more file types).
Combine this with list Comprehension, which provides a concise way to create lists.
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
filtered_d = {key:[item for item in value if item.split('.')[-1] in ['json','csv']] for key, value in d.items()}
you can check documentation here for more detail on list comprehension.

how to merge 2 dictionaries into a new dictionary in python

I'm trying to write a function that merges the items in multiple dictionaries under a single dictionary for matching keys.
For example, given
dict1 = {1:3, 2:4}
dict2 = {1:5, 2:6}
the function must return:
dict3 = {1:(3,5),2:(4,6)}
I also want the values to be numerically sorted, i.e. like this:
{1:(3,5)}
instead of this:
{1:(5,3)}
So far, I tried this, but it didn't work as I expected:
def mergeDicts(dict1, dict2):
dict3 = {**dict1, **dict2}
for key, value in dict3.items():
if key in dict1 and key in dict2:
dict3[key] = (value , dict1[key])
return dict3
You may use a defaultdict and a list as type of value, then iterate both dict1 and dict2 and their value in the list pointed by the key
def mergeDicts(dict1, dict2):
dict3 = defaultdict(list)
for key, value in dict1.items():
dict3[key].append(value)
for key, value in dict2.items():
dict3[key].append(value)
return dict(dict3)
Generic method that can accept any amount of dict as parameters
def mergeDicts(*dicts):
dict3 = defaultdict(list)
for d in dicts:
for key, value in d.items():
dict3[key].append(value)
return dict(dict3)
Achieving the same with dict-comprehension
def mergeDicts(dict1, dict2):
return {k: [dict1[k], dict2[k]] for k in dict1}
def mergeDicts(*dicts):
return {k: [d[k] for d in dicts] for k in dicts[0]}
You can do like this:
dict1 = {1:3, 2:4}
dict2 = {1:5, 2:6}
ds = [dict1, dict2]
d = {}
for k in dict1.iterkeys():
d[k] = tuple(d[k] for d in ds)
print(d)
I believe this is closer to what you want than the other answer.
def mergeDicts(dict1, dict2):
dict3 = {}
for key, value in dict1.items():
if key in dict2:
dict3[key] = (value, dict2[key])
return dict3
You could do it lke this:
dict1 = {1:3, 2:4}
dict2 = {1:5, 2:6}
def mergeDicts(dict1, dict2):
dict3 = {}
for key, value in dict1.items():
dict3[key] = (value, dict2[key])
return dict3
Assume keys are going to be same in both dictionary
def mergeDicts(dict1, dict2):
dict3 = {}
for i in dict1.keys():
dict3[i] = dict1[i], dict2[i]
return dict3
Assuming the dicts might have fully/partially different keys:
def mergeDicts(d1:dict, d2:dict):
keys=set(list(d1.keys())+list(d2.keys()))
keys_inter=set(d1.keys()).intersection(d2.keys())
d=dict()
for k in keys:
d[k]=[d1[k], d2[k]] if k in keys_inter else [(d1.get(k, None) or d2.get(k, None))]
return d
The following provides exactly the output that you are seeking.
from collections import defaultdict
from itertools import chain
dict1 = {1:3, 2:4}
dict2 = {1:5, 2:6}
dict3 = defaultdict(list)
for (k,v) in chain(dict1.items(), dict2.items()):
dict3[k].append(v)
for k in dict3.keys():
dict3[k] = tuple(dict3[k])
output
defaultdict(<class 'list'>, {1: (3, 5), 2: (4, 6)})

How to merge two dicts and combine common keys?

I would like to know how if there exists any python function to merge two dictionary and combine all values that have a common key.
I have found function to append two dict, to merge two dict but not to combine its values.
Example:
D1 = [{k1: v01}, {k3: v03}, {k4: v04},}],
D2 = [{k1: v11}, {k2: v12}, {k4: v14},}],
this should be the expected result:
D3 = [
{k1: [v01, v11]},
{k2: [ v12]},
{K3: [v03 ]},
{k4: [v04, v14]},
]
There is no built-in function for this but you can use a defaultdict for this:
from collections import defaultdict
d = defaultdict(list)
for other in [d1, d1]:
for k, v in other.items():
d[k].append(v)
A solution, without importing anything:
# First initialize data, done correctly here.
D1 = [{'k1': 'v01'}, {'k3': 'v03'}, {'k4': 'v04'}]
D2 = [{'k1': 'v11'}, {'k2': 'v12'}, {'k4': 'v14'}]
# Get all unique keys
keys = {k for d in [*D1, *D2] for k in d}
# Initialize an empty dict
D3 = {x:[] for x in keys}
# sort to maintain order
D3 = dict(sorted(D3.items()))
#Iterate and extend
for x in [*D1, *D2]:
for k,v in x.items():
D3[k].append(v)
# NOTE: I do not recommend you convert a dictionary into a list of records.
# Nonetheless, here is how it would be done.
# To convert to a list
D3_list = [{k:v} for k,v in D3.items()]
print(D3_list)
# [{'k1': ['v01', 'v11']},
# {'k2': ['v12']},
# {'k3': ['v03']},
# {'k4': ['v04', 'v14']}]
If you meant to use actual dicts, instead of lists of dicts, this is easier.
D1 = dict(k1=1, k3=3, k4=4)
D2 = dict(k1=11, k2=12, k4=14)
There isn't a simple built-in function to do this, but the setdefault method is close.
It tries to get the given key, but creates it if it doesn't exist.
D3 = {}
for k, v in D1.items() | D2.items():
D3.setdefault(k, set()).add(v)
And the result.
{'k4': {4, 14}, 'k1': {1, 11}, 'k3': {3}, 'k2': {12}}
This all assumes the order doesn't matter, just combining sets.
A more generic way to merge dicts together may look like this.
(To answer a similar SO question)
def merge(combiner, dicts):
new_dict = {}
for d in dicts:
for k, v in d.items():
if k in new_dict:
new_dict[k] = combiner(new_dict[k], v)
else:
new_dict[k] = v
return new_dict
x = {'a': 'A', 'b': 'B'}
y = {'b': 'B', 'c': 'C'}
z = {'a': 'A', 'd': 'D'}
merge_dicts(combiner= lambda x, y: f'{x} AND {y}', dicts=(x,y,z))
# {'a': 'A AND A', 'b': 'B AND B', 'c': 'C', 'd': 'D'}

How to remove dictionary key with known value?

Assume python dict:
mydict = {'a': 100, 'b': 200, 'c': 300}
I know one of the values:
value = 200
How to remove the 'b': 200 pair from the dict? I need this:
mydict = {'a': 100, 'c': 300}
Use a dictionary comprehension. Note that (as jonrsharpe has stated) this will create a new dictionary which excludes the key:value pair that you want to remove. If you want to delete it from your original dictionary then please see his answer.
>>> d = {'a': 100, 'b': 200, 'c': 300}
>>> val = 200
# Use d.items() for Python 2.x and d.iteritems() for Python 3.x
>>> d2 = {k:v for k,v in d.items() if v != val}
>>> d2
{'a': 100, 'c': 300}
It sounds like you want:
for key, val in list(mydict.items()):
if val == value:
del mydict[key]
break # unless you want to remove multiple occurences
You'll need to loop over every items(), either with dict comprehension:
new_dict = {k:v for k,v in my_dict.items() if predicate(value)}
Or modifying the existing dictionary:
for k,v in my_dict.items():
if not predicate(v):
del my_dict[k]
The simplest i found:
for key in [k for k,v in mydict.items() if v==200]:
del mydict[key]

Categories