Python Nested dictionary compare values internally - python

I am trying to process a dictionary with keys and each key having a list of values and create a nested dictionary from it. And also compare the values for equality in the list for each key and generate a new dictionary with the list of equal and unequal values.
I was able to loop through the list of values for each key and process them to get a new variable with which I wanted to create the new nested dictionary. But currently a null exception is thrown at the first key value.
dict1 = {a:[d,e,f], b:[p,q,r]}
dict2 = {d:100, e:100, f:100, p:100, q:100, r:100}
dict3 = {d:text1, e: text2, f: text3}
for i in dict1.keys():
for x in dict1[i]:
if dict2[x] == 100:
string = re.findall(r'sometext in text',dict3[x])[0]
ver = re.search('(?is)<i>(.+?)</i>', match_string).group(1)
d[i][x] = ver
Expected result:
d = { a:{d:ver1, e:ver2, f:ver3}, b:{p:ver4, q:ver5, r:ver6 }
After this looping through each nested value, each value needs to be compared with its peers value and arranged in a new dictionary with the keys of the values matching. Something as below:
if d's ver1 = e's ver2 =! f's ver3
dict4 = {a: { equal:[d,e], unequal: [f]}

I don't know where dict3 comes into play with your desired output but this will get the desired output:
dict1 = {'a':['d','e','f'], 'b':['p','q','r']}
dict2 = {'d':100, 'e':100, 'f':100, 'p':100, 'q':100, 'r':100}
result = {key1: {key2: dict2[key2] for key2 in val1} for key1, val1 in dict1.items()}
print(result)
Output:
{
"a": {
"d": 100,
"e": 100,
"f": 100
},
"b": {
"p": 100,
"q": 100,
"r": 100
}
}

Related

Python dictionary with key value pair as value for a key

I want to know how to create a dictionary with key value pair and value should have another values.
For example:
{key:{value1 : [a,b,c] , value2 : [d,e,f] , value3 : [g,h,i] } }
I tried,
a = {}
a.setdefault(key,{})[value] = a
a.setdefault(key,{})[value] = b
a.setdefault(key,{})[value] = c
then a returns
{ key: {value : c } }
For value last one added is only getting.
from collections import defaultdict
#create nested dict using defaultdict
a = defaultdict(lambda:defaultdict(list))
#above line will create dict of dict where internal dict holds list of values
a['key']['value'].append('a')
a['key']['value'].append('b')
a['key']['value'].append('c')
a looks like {'key':{'value':[a,b,c]}}
#To read data iterate over nested dict
for k,v in a.iteritems():
print k
print v['value']

Create dictionary based on matching terms from two other dictionaries - Python

I'm trying to compare two large dictionaries that describe the contents of product catalogs. Each dictionary consists of a unique, coded key and a list of terms for each key.
dict1 = {
"SKU001": ["Plumbing", "Pumps"],
"SKU002": ["Motors"],
"SKU003": ["Snow", "Blowers"],
"SKU004": ["Pnuematic", "Hose", "Pumps"],
...
}
dict2 = {
"FAS001": ["Pnuematic", "Pumps"],
"GRA001": ["Lawn", "Mowers"],
"FAS002": ["Servo", "Motors"],
"FAS003": ["Hose"],
"GRA002": ["Snow", "Shovels"],
"GRA003": ["Water", "Pumps"]
...
}
I want to create a new dictionary that borrows the keys from dict1 and whose values are a list of keys from dict2 where at least one of their term values match. The ideal end result may resemble this:
match_dict = {
"SKU001": ["FAS001", "GRA003"],
"SKU002": ["FAS002"],
"SKU003": ["GRA002"],
"SKU004": ["FAS001", "FAS003", "GRA003],
...
}
I'm having issues creating this output though. Is it possible to create a list of keys and assign it as a value to another key? I've made a few attempts using nested loops like below, but the output isn't as desired and I'm unsure if it's even working properly. Any help is appreciated!
matches = {}
for key, values in dict1.items():
for value in values:
if value in dict2.values():
matches[key] = value
print(matches)
This is one possible implementation:
dict1 = {
"SKU001": ["Plumbing", "Pumps"],
"SKU002": ["Motors"],
"SKU003": ["Snow", "Blowers"],
"SKU004": ["Pnuematic", "Hose", "Pumps"],
}
dict2 = {
"FAS001": ["Pnuematic", "Pumps"],
"GRA001": ["Lawn", "Mowers"],
"FAS002": ["Servo", "Motors"],
"FAS003": ["Hose"],
"GRA002": ["Snow", "Shovels"],
"GRA003": ["Water", "Pumps"]
}
match_dict_test = {
"SKU001": ["FAS001", "GRA003"],
"SKU002": ["FAS002"],
"SKU003": ["GRA002"],
"SKU004": ["FAS001", "FAS003", "GRA003"],
}
# Find keys for each item in dict2
dict2_reverse = {}
for k, v in dict2.items():
for item in v:
dict2_reverse.setdefault(item, []).append(k)
# Build dict of matches
match_dict = {}
for k, v in dict1.items():
# Keys in dict2 associated to each item
keys2 = (dict2_reverse.get(item, []) for item in v)
# Save sorted list of keys from dict2 without repetitions
match_dict[k] = sorted(set(k2i for k2 in keys2 for k2i in k2))
# Check result
print(match_dict == match_dict_test)
# True
Assuming that dict1 and dict2 can have duplicate value entries, you would need to build an intermediate multi-map dictionary and also handle uniqueness of the expanded value list for each SKU:
mapDict = dict()
for prod,attributes in dict2.items():
for attribute in attributes:
mapDict.setdefault(attribute,[]).append(prod)
matchDict = dict()
for sku,attributes in dict1.items():
for attribute in attributes:
matchDict.setdefault(sku,set()).update(mapDict.get(attribute,[]))
matchDict = { sku:sorted(prods) for sku,prods in matchDict.items() }
print(matchDict)
{'SKU001': ['FAS001', 'GRA003'], 'SKU002': ['FAS002'], 'SKU003': ['GRA002'], 'SKU004': ['FAS001', 'FAS003', 'GRA003']}

Appending parameters from a list in a for loop

I have a list with several data, ['a','b','c'...]
The goal here is to read all the items in the list and access to a json file to retrieve that information.
The json i have is as follows
{
"a": {
"b": {
"c": { .... }
}
} }
So, the final sentence to execute is
code.get(list[0]).get(list[1]).get(list[2]...get(list[n]
Is there any way i can do a for loop based on the length of the list to do this?
Something like, for any item in the list, append a ..get(list[i]) to my sentence
Thanks
Just iterate over the key list and go down into the code dict:
keys = ['a','b','c']
current_level = code # Top level
for key in keys:
current_level = current_level.get(key) # Descent next level
print current_level # Value of the 'c' dict

Using dictionary comprehenion, need more than 1 value to unpack

Consider you have JSON structured like below:
{
"valueA": "2",
"valueB": [
{
"key1": "value1"
},
{
"key2": "value2"
},
{
"key3": "value3"
}
]
}
and when doing something like:
dict_new = {key:value for (key,value) in dict['valueB'] if key == 'key2'}
I get:
ValueError: need more than 1 value to unpack
Why and how to fix it?
dict['valueB'] is a list of dictionaries. You need another layer of nesting for your code to work, and since you are looking for one key, you need to produce a list here (keys must be unique in a dictionary):
values = [value for d in dict['valueB'] for key, value in d.items() if key == 'key2']
If you tried to make a dictionary of key2: value pairs, you will only have the last pair left, as the previous values have been replaced by virtue of having been associated with the same key.
Better still, just grab that one key, no need to loop over all items if you just wanted that one key:
values = [d['key2'] for d in dict['valueB'] if 'key2' in d]
This filters on the list of dictionaries in the dict['valueB'] list; if 'key2' is a key in that nested dictionary, we extract it.

How to remove dictionary's keys and values based on another dictionary?

I wish to remove keys and values in one JSON dictionary based on another JSON dictionary's keys and values. In a sense I am looking perform a "subtraction". Let's say I have JSON dictionaries a and b:
a = {
"my_app":
{
"environment_variables":
{
"SOME_ENV_VAR":
[
"/tmp",
"tmp2"
]
},
"variables":
{ "my_var": "1",
"my_other_var": "2"
}
}
}
b = {
"my_app":
{
"environment_variables":
{
"SOME_ENV_VAR":
[
"/tmp"
]
},
"variables":
{ "my_var": "1" }
}
}
Imagine you could do a-b=c where c looks like this:
c = {
"my_app":
{
"environment_variables":
{
"SOME_ENV_VAR":
[
"/tmp2"
]
},
"variables":
{ "my_other_var": "2" }
}
}
How can this be done?
You can loop through your dictionary using for key in dictionary: and you can delete keys using del dictionary[key], I think that's all you need. See the documentation for dictionaries: https://docs.python.org/2/tutorial/datastructures.html#dictionaries
The way you can do it is to:
Create copy of a -> c;
Iterate over every key, value pair inside b;
Check if for same top keys you have same inner keys and values and delete them from c;
Remove keys with empty values.
You should modify code, if your case will be somehow different (no dict(dict), etc).
print(A)
print(B)
C = A.copy()
# INFO: Suppose your max depth is as follows: "A = dict(key:dict(), ...)"
for k0, v0 in B.items():
# Look for similiar outer keys (check if 'vars' or 'env_vars' in A)
if k0 in C:
# Look for similiar inner (keys, values)
for k1, v1 in v0.items():
# If we have e.g. 'my_var' in B and in C and values are the same
if k1 in C[k0] and v1 == C[k0][k1]:
del C[k0][k1]
# Remove empty 'vars', 'env_vars'
if not C[k0]:
del C[k0]
print(C)
{'environment_variables': {'SOME_ENV_VAR': ['/tmp']},
'variables': {'my_var': '2', 'someones_var': '1'}}
{'environment_variables': {'SOME_ENV_VAR': ['/tmp']},
'variables': {'my_var': '2'}}
{'variables': {'someones_var': '1'}}
The following does what you need:
def subtract(a, b):
result = {}
for key, value in a.items():
if key not in b or b[key] != value:
if not isinstance(value, dict):
if isinstance(value, list):
result[key] = [item for item in value if item not in b[key]]
else:
result[key] = value
continue
inner_dict = subtract(value, b[key])
if len(inner_dict) > 0:
result[key] = inner_dict
return result
It checks if both key and value are present. It could del items, but I think is much better to return a new dict with the desired data instead of modifying the original.
c = subtract(a, b)
UPDATE
I have just updated for the latest version of the data provided by in the question. Now it 'subtract' list values as well.
UPDATE 2
Working example: ipython notebook

Categories