Flo
Flo

Reputation: 429

Python: Search for a list of nested dict in a list of nested dict

Let's say we have:

stack = [
         {'id': '1', 'name': {'firstname': 'bob', 'lastname': 'smith'}},
         {'id': '2', 'name': {'firstname': 'jane', 'lastname': 'abb'}},
         {'id': '3', 'name': {'firstname': 'flo', 'lastname': 'gram', 'middle': 'remi'}},
         {'id': '4', 'name': {'firstname': 'frank', 'lastname': 'glow'}, 'partner': 'diane'}
]
needles = [{'name':{'lastname': 'gram'}},
          {'partner': 'diane'}
]

We'd like a function find, like so:

list = find(needles, stack)
print(list)
>[{id: '3', name: {firstname: 'flo', lastname: 'gram', middle: 'remi'}}, {id: '4', name: {firstname: 'frank', lastname: 'glow'}, partner: 'diane'}]

At first I wanted to use items(), like so:

def find(needle, stack):
    result = []
    for needle in needles:
        for item in stack:
            if needle.items() <= item.items():
                result.append()

But this returns:

[{'id': '4', 'name': {'firstname': 'frank', 'lastname': 'glow'}, 'partner': 'diane'}]

Because the item match has to be exact, I would have to pass ['name': {'firstname': 'flo', 'lastname': 'gram', 'middle': 'remi'}, {'partner': 'diane'}' for my function to return the desired result.

I am not sure where to go from here. Since my stack can be nested for an unknown depth ({a:{b:{c:value}}}) the solution might be some sort of recursion but it might not be necessary since I want to check for the exact 'path' (keys) in needle. It comes down to partially match needle items with stack items.

Upvotes: 1

Views: 55

Answers (1)

Ajax1234
Ajax1234

Reputation: 71451

You can use recursion:

def find(n, s):
   def exists(n, d):
      if type(n) != type(d):
         return False
      if not isinstance(n, (dict, list)):
          return n == d
      if isinstance(n, list):
          return any(exists(j, k) for j in n for k in d)
      return all(exists(b, d.get(a, None)) for a, b in n.items())
   return [i for i in s if any(exists(j, i) for j in n)]

stack = [{'id': '1', 'name': {'firstname': 'bob', 'lastname': 'smith'}}, {'id': '2', 'name': {'firstname': 'jane', 'lastname': 'abb'}}, {'id': '3', 'name': {'firstname': 'flo', 'lastname': 'gram', 'middle': 'remi'}}, {'id': '4', 'name': {'firstname': 'frank', 'lastname': 'glow'}, 'partner': 'diane'}, {'id': '5', 'name': {'firstname': ['flo', 'Flo'], 'lastname': 'gram', 'middle': 'remi'}}]
needles = [{'name': {'lastname': 'gram'}}, {'partner': 'diane'}, {'name':{'firstname':['Flo']}}]
results = find(needles, stack)

Output:

[{'id': '3', 'name': {'firstname': 'flo', 'lastname': 'gram', 'middle': 'remi'}}, 
 {'id': '4', 'name': {'firstname': 'frank', 'lastname': 'glow'}, 'partner': 'diane'}, 
 {'id': '5', 'name': {'firstname': ['flo', 'Flo'], 'lastname': 'gram', 'middle': 'remi'}}]

Upvotes: 1

Related Questions