Albert
Albert

Reputation: 75

Get dictionaries in a list where the key:value pairs are in another list of dictionaries

I have two lists of dictionaries, e.g.

L1 = [
    {'ID': '1', 'file': 'test1', 'ext': 'txt'},
    {'ID': '2', 'file': 'test2', 'ext': 'txt'},
    {'ID': '3', 'file': 'test3', 'ext': 'py'}
]

L2 = [
    {'file': 'test1', 'ext': 'txt', 'val': '5'},
    {'file': 'test3', 'ext': 'py', 'val': '7'},
    {'file': 'test4', 'ext': 'py', 'val': '8'}
]

I want to extract all dictionaries from L1 where the key:value pairs of 'file' and 'ext' can be found in a dictionary of L2.

In our case

L = [
    {'ID': '1', 'ext': 'txt', 'file': 'test1'},
    {'ID': '3', 'ext': 'py', 'file': 'test3'}
]

Is there a smart pythonic way to do this?

Upvotes: 2

Views: 79

Answers (3)

Mike Müller
Mike Müller

Reputation: 85492

Using your input:

L1 = [
    {'ID': '1', 'file': 'test1', 'ext': 'txt'},
    {'ID': '2', 'file': 'test2', 'ext': 'txt'},
    {'ID': '3', 'file': 'test3', 'ext': 'py'}
]

L2 = [
    {'file': 'test1', 'ext': 'txt', 'val': '5'},
    {'file': 'test3', 'ext': 'py', 'val': '7'},
    {'file': 'test4', 'ext': 'py', 'val': '8'}
]

You can extract the file-ext pairs first in a set:

pairs = {(d['file'], d['ext']) for d in L2 for k in d}

and filter them in a second step:

[d for d in L1 if (d['file'], d['ext']) in pairs]

Result:

[{'ID': '1', 'ext': 'txt', 'file': 'test1'},
 {'ID': '3', 'ext': 'py', 'file': 'test3'}]

Upvotes: 1

Inbar Rose
Inbar Rose

Reputation: 43457

Here is a generic function (robust) that will accept match key parameters.

def extract_matching_dictionaries(l1, l2, mk):
    return [d1 for d1 in l1 if all(k in d1 for k in mk) and
            any(all(d1[k] == d2[k] for k in mk) for d2 in l2 if all(k in d2 for k in mk))]

Example:

>>> extract_matching_dictionaries(L1, L2, ['file', 'ext'])
[{'ID': '1', 'ext': 'txt', 'file': 'test1'},
 {'ID': '3', 'ext': 'py', 'file': 'test3'}]

Upvotes: 2

gtlambert
gtlambert

Reputation: 11961

You could use the following list comprehension:

L1 = [
    {'ID':'1','file':'test1','ext':'txt'},
    {'ID':'2','file':'test2','ext':'txt'},
    {'ID':'3','file':'test3','ext':'py'}
]

L2 = [
    {'file':'test1','ext':'txt','val':'5'},
    {'file':'test3','ext':'py','val':'7'},
    {'file':'test4','ext':'py','val':'8'}
]


L = [d1 for d1 in L1 if any(
         d2.get('file') == d1['file'] and d2.get('ext') == d1['ext'] for d2 in L2)]
print(L)

Output

[{'ID': '1', 'ext': 'txt', 'file': 'test1'},
 {'ID': '3', 'ext': 'py', 'file': 'test3'}]

This iterates over each dictionary d1 in L1, and for each one tests if both the key:value pairs of d1['file'] and d1['ext'] exist in any of the dictionaries in L2.

Upvotes: 4

Related Questions