Reputation:
I have a dictionary that has another list of dictionaries as a value for one of the keys. I need to iterate through this nested dictionary and compare it to another list of dictionaries. Any dictionary that is in the other list that is not already in this one, should be added. The nested list of dictionaries looks like this:
{
"rules": [
{
"name": "Rule 1",
"severity": "High"
},
{
"name": "Rule 2 ",
"severity": "Medium"
}],
"Account":11111,
"Name": "Test Account"
}
The second dictionary is as follows:
[{
"name": "Rule 2",
"severity": "Medium"
},
{
"name": "Rule 3",
"severity": "low"
}]
So Rule 3 should be added to the "rules"
list in the first dictionary and Rule 2 ignored.
I got this far, but the logic is not working if I continue down this path, and results in very complicated nested if statements. My programming skills are very novice:
for k, v in bundle.items():
i = bundle["rules"]
for entity in i:
for key, value in entity.items():
Upvotes: 1
Views: 942
Reputation: 15130
If the only value that really needs to be compared is the rule name, then you could just derive a list of the current rule names and check for name matches while looping through the new rules to be tested.
data = {
"rules": [{"name": "Rule 1", "severity": "High"}, {"name": "Rule 2", "severity": "Medium"}],
"Account": 11111,
"Name": "Test Account"
}
test_rules = [{"name": "Rule 2", "severity": "Medium"}, {"name": "Rule 3", "severity": "Low"}]
rules = data['rules']
names = [r['name'] for r in rules]
for rule in test_rules:
if rule['name'] not in names:
rules.append(rule)
print(data)
# OUTPUT
# {
# 'rules': [
# {'name': 'Rule 1', 'severity': 'High'},
# {'name': 'Rule 2', 'severity': 'Medium'},
# {'name': 'Rule 3', 'severity': 'Low'}
# ],
# 'Account': 11111,
# 'Name': 'Test Account'
# }
Assuming the name comparison is all that matters based on your dataset, this approach is a bit faster than converting to a set of tuples and then converting the comparison data to tuples in the loop.
Upvotes: 0
Reputation: 5460
As blhsign suggests, you should use a set. This requires making your rules a hashable type. I suggest namedtuple
. Then, instead of iterating over items, use the nature of sets to your benefit:
from collections import namedtuple
d = {
"rules": [
{
"name": "Rule 1",
"severity": "High"
},
{
"name": "Rule 2",
"severity": "Medium"
}],
"Account":11111,
"Name": "Test Account"
}
rule_tuple = namedtuple('Rule', ['name', 'severity'])
d['rules'] = {rule_tuple(**rule) for rule in d['rules']}
new_rules = [
{
"name": "Rule 2",
"severity": "Medium"
},
{
"name": "Rule 3",
"severity": "low"
}
]
new_rules = {rule_tuple(**rule) for rule in new_rules}
d['rules'] = d['rules'].union(new_rules)
d
Output:
{'rules': {Rule(name='Rule 1', severity='High'),
Rule(name='Rule 2', severity='Medium'),
Rule(name='Rule 3', severity='low')},
'Account': 11111,
'Name': 'Test Account'}
Upvotes: 0
Reputation: 106588
You can convert the existing rules to a set first for efficient lookup:
d = {
"rules": [
{
"name": "Rule 1",
"severity": "High"
},
{
"name": "Rule 2",
"severity": "Medium"
}],
"Account":11111,
"Name": "Test Account"
}
new = [{ "name": "Rule 2", "severity": "Medium" }, { "name": "Rule 3", "severity": "low" }]
set_d = set(tuple(r.items()) for r in d['rules'])
for r in new:
if tuple(r.items()) not in set_d:
d['rules'].append(r)
print(d)
This outputs:
{'rules': [{'name': 'Rule 1', 'severity': 'High'}, {'name': 'Rule 2', 'severity': 'Medium'}, {'name': 'Rule 3', 'severity': 'low'}], 'Account': 11111, 'Name': 'Test Account'}
Upvotes: 1