Home > OS >  Recursive dictionary searching
Recursive dictionary searching

Time:01-29

I'm trying to make a function that would take nested array (dict/list in any order) and a key name as arguments and return all values of that key in a list.

my_key = "Items"

my_dict = [{'z': 0, 'x': 0, 'y': 0, 'Items': [{'Slot': 1, 'id': 'minecraft:rail', 'Count': 1}, {'Slot': 2, 'id': 'minecraft:white_shulker_box', 'tag': {'BlockEntityTag': {'id': 'minecraft:shulker_box', 'Items': [{'Slot': 0, 'Count': 1, 'tag': {'Items': [{'id': 'minecraft:amethyst_shard', 'Count': 1}]}, 'id': 'minecraft:bundle'}]}}, 'Count': 1}]}]

def recursive_lookup(data, key):
    if isinstance(data, list):
        for i in data:
            recursive_lookup(i, key)
    elif isinstance(data, dict):
        for i, v in data.items():
            if i == key:
                print(f'{v = }')
            if isinstance(v, list) or isinstance(v, dict): recursive_lookup(v, key)
print(recursive_lookup(my_dict, my_key))

Currently it prints out found items at print(f'{v = }'). How can I store those in a list and pass as a function return?

CodePudding user response:

You can use .extend() to concatenate the result of recursive calls to a list.

def recursive_lookup(data, key):
    values = []
    if isinstance(data, list):
        for i in data:
            values.extend(recursive_lookup(i, key))
    elif isinstance(data, dict):
        for i, v in data.items():
            if i == key:
                values.append(v)
            if isinstance(v, list) or isinstance(v, dict):
                values.extend(recursive_lookup(v, key))
    return values

CodePudding user response:

You can what you want without any explicit recursion at all by making use of the json module in the standard library (assuming your data can be serialized into that format). This is because the JSON decoder supports an object_hook argument which is a function it will call everytime it encounters a dictionary.

The basic idea is to specify a function via this argument that merely "watches" what is being decoded and checks it for the sought-after key.

Here's what I mean:

import json

my_key = "Items"
my_dict = [{'z': 0, 'x': 0, 'y': 0, 'Items': [{'Slot': 1, 'id': 'minecraft:rail', 'Count': 1}, {'Slot': 2, 'id': 'minecraft:white_shulker_box', 'tag': {'BlockEntityTag': {'id': 'minecraft:shulker_box', 'Items': [{'Slot': 0, 'Count': 1, 'tag': {'Items': [{'id': 'minecraft:amethyst_shard', 'Count': 1}]}, 'id': 'minecraft:bundle'}]}}, 'Count': 1}]}]

def lookup(data, key):
    results = []

    def decode_dict(a_dict):
        try:
            results.append(a_dict[key])
        except KeyError:
            pass
        return a_dict

    json_repr = json.dumps(data)  # Convert to JSON format.
    json.loads(json_repr, object_hook=decode_dict)  # Return value ignored.
    return results

from pprint import pprint
pprint(lookup(my_dict, my_key), sort_dicts=False)

Pretty-printed result list:

[[{'id': 'minecraft:amethyst_shard', 'Count': 1}],
 [{'Slot': 0,
   'Count': 1,
   'tag': {'Items': [{'id': 'minecraft:amethyst_shard', 'Count': 1}]},
   'id': 'minecraft:bundle'}],
 [{'Slot': 1, 'id': 'minecraft:rail', 'Count': 1},
  {'Slot': 2,
   'id': 'minecraft:white_shulker_box',
   'tag': {'BlockEntityTag': {'id': 'minecraft:shulker_box',
                              'Items': [{'Slot': 0,
                                         'Count': 1,
                                         'tag': {'Items': [{'id': 'minecraft:amethyst_shard',
                                                            'Count': 1}]},
                                         'id': 'minecraft:bundle'}]}},
   'Count': 1}]]

CodePudding user response:

You can keep a running list:

def recursive_lookup(data, key):
    lst = []
    if isinstance(data, list):
        for i in data:
            lst.append(recursive_lookup(i, key))
    elif isinstance(data, dict):
        for i, v in data.items():
            if i == key:
                lst.append([v])
            if isinstance(v, list) or isinstance(v, dict): lst.append(recursive_lookup(v, key))
    return lst

print(recursive_lookup(data, 'Items'))
  •  Tags:  
  • Related