Новый диктант отфильтрован по элементу

#python-3.x #dictionary #arraylist #key #key-value

Вопрос:

Не могли бы вы помочь мне с этой простой вещью, к сожалению, я ее не понимаю.

У меня есть этот список с двумя другими списками со списками диктовок (но это может быть больше списков).

 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': ''}
    ]
]
 

Моя цель-получить окончательный список объединенных диктов, полученных с помощью правила («объединить все дикты, содержащие поле «INTF» с одинаковым номером , в данном случае 77 или 0, другими словами, отфильтровать по номеру интерфейса»).

Как это

 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': ''}
       ]
 

Комментарии:

1. Привет, для сообщества важно, чтобы вы продемонстрировали, что вы также работаете над решением своей проблемы. Лучший способ сделать это-включить текстовую версию кода, которую вы используете сейчас, даже если она работает не совсем правильно. Также очень полезно увидеть, чего вы хотите в результате.

2. Если вы хотите подтолкнуть к началу работы, у меня есть решение, основанное на re.findall() и или collections.defaultdict() или setdefault() .

3. Джонс, мне была бы полезна любая помощь. Я понимаю, что мой вопрос может дублировать некоторые, но я с трудом понимаю, как найти короткое решение =)

Ответ №1:

Поскольку мы хотим объединить dicts данные на основе ключа, я думаю, что лучше всего начать с изменения наших данных, чтобы облегчить поиск по ключу. В то время как мы изменяем данные, давайте также создадим ключ, который будет просто номером.

 import re
a_reshaped = [
    {re.search(r'd ', x["INTF"]): x for x in y}
    for y in a
]
print(a_reshaped )
 

Это даст нам:

 [
    {
        '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': ''}
    }
]
 

На этом этапе мы можем повторить a_reshaped и объединить диктанты на основе ключа. Мы можем основать эту часть на любом setdefault() или collections.defaultdict() . Я сам предпочитаю второе.

 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()))
 

Давая нам:

 [
    {'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': ''}
]
 

Полное решение, основанное на collections.defaultdict() том, чтобы быть:

 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()))
 

или на основе setdefault() как:

 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()))
 

Оба дадут тебе:

 [
    {'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': ''}
]