Could you help me with this simple stuff, unfortunately I don't get it.
I have this a list with two another lists with lists of dicts (but it can be more lists).
a = [
[
{'DESCRIP': '', 'INTF': 'Vl77', 'PROTOCOL': 'up', 'STATUS': 'up'},
{'DESCRIP': '', 'INTF': 'Fa0', 'PROTOCOL': 'down', 'STATUS': 'admin down'}
],
[
{'INBOUND_ACL': '', 'INTF': 'Vlan77', 'IPADDR': ['192.168.77.11/24'], 'IP_HELPER': [], 'LINK_STATUS': 'up', 'MTU': '1500', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'up', 'VRF': ''},
{'INBOUND_ACL': '', 'INTF': 'FastEthernet0', 'IPADDR': [], 'IP_HELPER': [], 'LINK_STATUS': 'administratively down', 'MTU': '', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'down', 'VRF': ''}
]
]
My goal is to get a final list of merged dicts, derived by a rule ('merge all dicts that contain the 'INTF' field with the same number, in this case 77 or 0 , in other words to filter by interface number').
Like that
new_dict = [
{'DESCRIP': '', 'PROTOCOL': 'up', 'STATUS': 'up','INBOUND_ACL': '', 'INTF': 'Vlan77', 'IPADDR': ['192.168.77.11/24'], 'IP_HELPER': [], 'LINK_STATUS': 'up','MTU': '1500', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'up', 'VRF': ''},
{'DESCRIP': '', 'PROTOCOL': 'down', 'STATUS': 'admin down','INBOUND_ACL': '', 'INTF': 'FastEthernet0', 'IPADDR': [], 'IP_HELPER': [], 'LINK_STATUS': 'administratively down', 'MTU': '', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'down', 'VRF': ''}
]
Since we are looking to merge dicts
based on a key, I think the best place to start will be to reshape our data to facilitate a key based lookup. While we are reshaping the data, let's also create a key that is just the number.
import re
a_reshaped = [
{re.search(r'\d+', x["INTF"]): x for x in y}
for y in a
]
print(a_reshaped )
This will give us:
[
{
'77': {'DESCRIP': '', 'INTF': 'Vl77', 'PROTOCOL': 'up', 'STATUS': 'up'},
'0': {'DESCRIP': '', 'INTF': 'Fa0', 'PROTOCOL': 'down', 'STATUS': 'admin down'}
},
{
'77': {'INBOUND_ACL': '', 'INTF': 'Vlan77', 'IPADDR': ['192.168.77.11/24'], 'IP_HELPER': [], 'LINK_STATUS': 'up', 'MTU': '1500', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'up', 'VRF': ''},
'0': {'INBOUND_ACL': '', 'INTF': 'FastEthernet0', 'IPADDR': [], 'IP_HELPER': [], 'LINK_STATUS': 'administratively down', 'MTU': '', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'down', 'VRF': ''}
}
]
At this point we can iterate over a_reshaped
and merge the dicts based on the key. We can base this part on either setdefault()
or collections.defaultdict()
. I prefer the second myself.
import collections
results = collections.defaultdict(dict)
for c in a_reshaped:
for key, value in c.items():
results[key] = {**results[key], **value}
print(list(results.values()))
Giving us:
[
{'DESCRIP': '', 'INTF': 'Vlan77', 'PROTOCOL': 'up', 'STATUS': 'up', 'INBOUND_ACL': '', 'IPADDR': ['192.168.77.11/24'], 'IP_HELPER': [], 'LINK_STATUS': 'up', 'MTU': '1500', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'up', 'VRF': ''},
{'DESCRIP': '', 'INTF': 'FastEthernet0', 'PROTOCOL': 'down', 'STATUS': 'admin down', 'INBOUND_ACL': '', 'IPADDR': [], 'IP_HELPER': [], 'LINK_STATUS': 'administratively down', 'MTU': '', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'down', 'VRF': ''}
]
The complete solution based on collections.defaultdict()
being:
import re
import collections
a = [
[
{'DESCRIP': '', 'INTF': 'Vl77', 'PROTOCOL': 'up', 'STATUS': 'up'},
{'DESCRIP': '', 'INTF': 'Fa0', 'PROTOCOL': 'down', 'STATUS': 'admin down'}
],
[
{'INBOUND_ACL': '', 'INTF': 'Vlan77', 'IPADDR': ['192.168.77.11/24'], 'IP_HELPER': [], 'LINK_STATUS': 'up', 'MTU': '1500', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'up', 'VRF': ''},
{'INBOUND_ACL': '', 'INTF': 'FastEthernet0', 'IPADDR': [], 'IP_HELPER': [], 'LINK_STATUS': 'administratively down', 'MTU': '', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'down', 'VRF': ''}
]
]
a_reshaped = [
{re.search(r'\d+', x["INTF"]).group(): x for x in y}
for y in a
]
results = collections.defaultdict(dict)
for c in a_reshaped:
for key, value in c.items():
results[key] = {**results[key], **value}
print(list(results.values()))
or based on setdefault()
as:
import re
a = [
[
{'DESCRIP': '', 'INTF': 'Vl77', 'PROTOCOL': 'up', 'STATUS': 'up'},
{'DESCRIP': '', 'INTF': 'Fa0', 'PROTOCOL': 'down', 'STATUS': 'admin down'}
],
[
{'INBOUND_ACL': '', 'INTF': 'Vlan77', 'IPADDR': ['192.168.77.11/24'], 'IP_HELPER': [], 'LINK_STATUS': 'up', 'MTU': '1500', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'up', 'VRF': ''},
{'INBOUND_ACL': '', 'INTF': 'FastEthernet0', 'IPADDR': [], 'IP_HELPER': [], 'LINK_STATUS': 'administratively down', 'MTU': '', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'down', 'VRF': ''}
]
]
a_reshaped = [
{re.search(r'\d+', x["INTF"]).group(): x for x in y}
for y in a
]
results = {}
for c in a_reshaped:
for key, value in c.items():
results[key] = {**results.setdefault(key, {}), **value}
print(list(results.values()))
Both will give you:
[
{'DESCRIP': '', 'INTF': 'Vlan77', 'PROTOCOL': 'up', 'STATUS': 'up', 'INBOUND_ACL': '', 'IPADDR': ['192.168.77.11/24'], 'IP_HELPER': [], 'LINK_STATUS': 'up', 'MTU': '1500', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'up', 'VRF': ''},
{'DESCRIP': '', 'INTF': 'FastEthernet0', 'PROTOCOL': 'down', 'STATUS': 'admin down', 'INBOUND_ACL': '', 'IPADDR': [], 'IP_HELPER': [], 'LINK_STATUS': 'administratively down', 'MTU': '', 'OUTGOING_ACL': '', 'PROTOCOL_STATUS': 'down', 'VRF': ''}
]