简体   繁体   中英

Manipulating a list of dictionaries based on values in another list

So basically I have three lists like so:

list1 = [{
    'IP' : "1.1.1.1", 
    'ID' : 1,
    },
    {
    'IP' : "2.2.2.2", 
    'ID' : 2
    }]

list2 = [{
    'vulnerability_id' : 4567, 
    'ID' : 1,
    },
    {
    'vulnerability_id' : 6578, 
    'ID' : 2
    }]

list3 = [{
    'vulnerability_id' : 4567, 
    'description' : 'blah',
    },
    {
    'vulnerability_id' : 6578, 
    'description' : 'blah blah'
    }]

What I need to do is get the description of an vulnerability based on an IP but this probably requires some sort of list comprehension and im not sure how to go about that. (And put it in a new dictionary)

I need to check the IP value I have, say 1.1.1.1, then compare it's ID with list2, then compare the associated 'vulnerability_id' in list3.

Any help would be greatly appreciated, if this doesn't make sense, please say and I will try and expand.

This is really heavy in terms of computing, but you only have lists as data sources, so, here is my "solution":

results = []
for ip_info in list1:
    result = {}
    result['ip'] = ip_info['IP']
    result['vulnerability'] = next((
            vuln_info['vulnerability_id']
            for vuln_info in list2
            if vuln_info['ID'] == ip_info['ID']
        ),None)

    result['description'] = next((
            desc_info['description']
            for desc_info in list3
            if desc_info['vulnerability_id'] == result['vulnerability']
        ),None)

    results.append(result)

Results:

[{'description': 'blah', 'ip': '1.1.1.1', 'vulnerability': 4567},
 {'description': 'blah blah', 'ip': '2.2.2.2', 'vulnerability': 6578}]

EDIT: improvement based on my answer and @Alex Hall answer:

def find(l, match, v, k):
    return next((x[k] for x in l if x[match] == v), None)

results = []
for ip_info in list1:
    ip = ip_info['IP']
    _id = ip_info['ID']
    vul = find(list2, 'ID', _id, 'vulnerability_id')
    desc = find(list3, 'vulnerability_id', vulnerability, 'description')    
    results.append(dict(ip=ip, vulnerability=vul, description=desc))
list1 = [
    {
        'IP': '1.1.1.1',
        'ID': 1,
    },
    {
        'IP': '2.2.2.2',
        'ID': 2
    }]

list2 = [
    {
        'vulnerability_id': 4567,
        'ID': 1,
    },
    {
        'vulnerability_id': 6578,
        'ID': 2
    }]

list3 = [
    {
        'vulnerability_id': 4567,
        'description': 'blah',
    },
    {
        'vulnerability_id': 6578,
        'description': 'blah blah'
    }]


def find(data, key, value):
    for row in data:
        if row[key] == value:
            return row
    raise ValueError('Row with %s = %s not found' % (key, value))


ID = find(list1, 'IP', '1.1.1.1')['ID']
vulnerability_id = find(list2, 'ID', ID)['vulnerability_id']
print(find(list3, 'vulnerability_id', vulnerability_id)['description'])

For things like this, I really like using the pandas package. I was able to do something like this:

import pandas as pd

list1 = [{
'IP' : "1.1.1.1", 
'ID' : 1,
},
{
'IP' : "2.2.2.2", 
'ID' : 2
}]

list2 = [{
'vulnerability_id' : 4567, 
'ID' : 1,
},
{
'vulnerability_id' : 6578, 
'ID' : 2
}]

list3 = [{
'vulnerability_id' : 4567, 
'description' : 'blah',
},
{
'vulnerability_id' : 6578, 
'description' : 'blah blah'
}]

df_1 = pd.DataFrame(list1)
df_2 = pd.DataFrame(list2)
df_3 = pd.DataFrame(list3)

output = df_1.merge(df_2).merge(df_3)

print output

ID       IP  vulnerability_id description
 1  1.1.1.1              4567        blah
 2  2.2.2.2              6578   blah blah

This will also give you that nicely formatted table at the end. With no extra work on your part! The merge operation is taking advantage of how well your dictionary keys are named. Since list1 and list2 both have id in common, it essentially performs an innerjoin on the id column. Then uses the resulting frame's vulnerability_id column to join with list3. This gets more complicated when you have more than one common key (in the sense that you will have to play around with some of the kwargs for the merge function to handle the excess overlap), but for this situation it works great :). The downside is that it does require installation of an external package, whereas the two solutions mentioned above do not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM