0

Let's assume I have a dictionary looks like this, where every instance of bakery_items will contain key-value pairs, of which the value is a dictionary itself:

{     "bakery_items" : {"pie":{"iscake" : "no", "edible" : "yes"}, "cheesecake":{"iscake" : "yes", "edible" : "yes"}, "shoe":{"iscake" : "no", "edible" : "no"}}
      "key1" : "blah",
      "key2" : "blah blah",
      "nestedlist" : [ 
        { "bakery_items" : {"potato":{"iscake" : "no", "edible" : "yes"}, "pound_cake":{"iscake" : "yes", "edible" : "yes"}, "scale":{"iscake" : "no", "edible" : "no"}},
          "nestednestedlist" : [ 
            { "bakery_items" : {"pomegranate":{"iscake" : "no", "edible" : "yes"}, "sponge_cake":{"iscake" : "yes", "edible" : "yes"}, "sandal":{"iscake" : "no", "edible" : "no"}},
              "keyA" : "blah blah blah" },
            { "bakery_items" : {"pickle":{"iscake" : "no", "edible" : "yes"}, "red_velvet":{"iscake" : "yes", "edible" : "yes"}, "screwdriver":{"iscake" : "no", "edible" : "no"}},
              "keyZ" : "blah blah blah" }],
          "anothernestednestedlist" : [ 
            { "bakery_items" : {"pizza":{"iscake" : "no", "edible" : "yes"}, "fruitcake":{"iscake" : "yes", "edible" : "yes"}, "scissor":{"iscake" : "no", "edible" : "no"}},
              "keyQ" : "blah blah" },
            { "bakery_items" : {"plum":{"iscake" : "no", "edible" : "yes"}, "pancake":{"iscake" : "yno", "edible" : "yes"}, "scratchpad":{"iscake" : "no", "edible" : "no"}},
              "keyW" : "blah" }] } ] } 

I am able to find the bakery_items as a list thanks to this answer to this question, but assume I don't need details about non-cake items (i.e bakery_items will only include key-value pairs that have iscake as yes). The final result should look like this:

{     "bakery_items" : {"cheesecake":{"iscake" : "yes", "edible" : "yes"}}
      "key1" : "blah",
      "key2" : "blah blah",
      "nestedlist" : [ 
        { "bakery_items" : {"pound_cake":{"iscake" : "yes", "edible" : "yes"}},
          "nestednestedlist" : [ 
            { "bakery_items" : {"sponge_cake":{"iscake" : "yes", "edible" : "yes"}},
              "keyA" : "blah blah blah" },
            { "bakery_items" : {"red_velvet":{"iscake" : "yes", "edible" : "yes"}},
              "keyZ" : "blah blah blah" }],
          "anothernestednestedlist" : [ 
            { "bakery_items" : {"fruitcake":{"iscake" : "yes", "edible" : "yes"}},
              "keyQ" : "blah blah" },
            { "bakery_items" : {},
              "keyW" : "blah" }] } ] } 

How can I make sure I find all occurrences bakery_items in such a nested structure, and at the same time make it so that I only have items that are cakes?

NOTE: The example is based on the example given by Matt Swain in this question. I am using Python 3.x if it matters.

  • 1
    So, to confirm: you want to filter the nested dictionary at all levels to only have dictionaries that meet some key constraint for the attributes? And is it OK to assume the nested dictionaries will at least have a `bakery_items` key at every level? And that every item in that will always have a `iscake` key? – Grismar Dec 02 '20 at 23:46
  • @Grismar I want to filter out the dictionaries under `bakery_items` if they are are not cake (i.e. `iscake` is a `no`). There does not have to be a `bakery_items` at every level. You can assume every `bakery_items` element will have an `iscake` value. – walkerelbert Dec 03 '20 at 00:00

1 Answers1

0

Assuming that:

  • every bakery_items value has an iscake value
  • you want to inpect every list element in the dictionary to see if there's nested dictionaries in there

Then your code could be (assuming your dictionary is source):

source = { }  # your dictionary here, with typos like missing commas fixed


def filter_for_cake(d):
    return {
        key: {
            k: v for k, v in value.items() if v['iscake'] == 'yes'
        } if key == 'bakery_items' else
        [
            x if not isinstance(x, dict) else filter_for_cake(x)
            for x in value
        ] if isinstance(value, list) else value
        for key, value in d.items()
    }

print(filter_for_cake(source))

Some explanation:

  • the function iterates over an entire dictionary
  • for each value that has 'bakery_items' as a key, it assumes it is a dictionary and filters it down to only those elements that have their 'iscake' set to 'yes'
  • for the other values, if the value is a list, it generates a copy, but passes each dictionary to filter_for_cake again (recursion)
  • for the remaining values, it just leaves them in as is
Grismar
  • 27,561
  • 4
  • 31
  • 54