简体   繁体   中英

Iterate over nested yaml dictionary from python

I have safe loaded python object by parsing the yaml document similar to below format,

envdata = yaml.safe_load(data)

id: XXX
name: XXX
tecVersion: 1

wrapper: #category
    wrapper-box-1: #instance
        host: XXX
        port: 4567
        tags:
          - ABC
          - VTR


powerWrapper: #category
     pw-box-45: #instance
         host: YYY
         port: 7890
         tags:
           - ABC

Each category is a top level array object and instance is an array object inside the category.

Requirement is, given the tag ex: ABC, I want to get all the matching instances in every category as a list. How can I iterate over each and every element and compare the tags and add all matching instances to a array of instances in an optimal way ?

(1.) Each category is a top level array object and instance is an array object inside the category.

(2.) How can I ... compare the tags and add all matching instances to a array of instances ... ?

The definition in (1.) is not exactly terrific, but it's enough to work with. I disagree with your use of the word "array" or list , when apparently a "map" or dict is what the category contains. It would be a bit nicer, I feel, if each instance was guaranteed to contain a key named 'instance' or 'id' or something, to distinguish them from sibling entries such as 'tecVersion' . Alternatively, all instances might be pushed one level down under a key with a creative name, such as, let's see, maybe we'd call it 'instances' ?

You made it clear that 'wrapper' is a "category". I don't know what 'wrapper-box-1' might be called. It's too bad you didn't also include a 'wrapper-box-2' in your example data.

Here is what yaml returns:

>>> pprint.pprint(envdata)
{'id': 'XXX',
 'name': 'XXX',
 'powerWrapper': {'pw-box-45': {'host': 'YYY', 'port': 7890, 'tags': ['ABC']}},
 'tecVersion': 1,
 'wrapper': {'wrapper-box-1': {'host': 'XXX',
                               'port': 4567,
                               'tags': ['ABC', 'VTR']}}}

Ok, let's iterate:

def get_tags(putative_category):
    """Generator, returns tags if the input appears to be a category."""
    try:
        for undefined_box_concept, attributes in putative_category.items():
            tags = attributes['tags']
            yield tags
    except (AttributeError, KeyError):
        pass

for category_name, category in envdata.items():
    for tags in get_tags(category):
        print(tags, category_name, category)

Output:

['ABC', 'VTR'] wrapper {'wrapper-box-1': {'host': 'XXX', 'port': 4567, 'tags': ['ABC', 'VTR']}}
['ABC'] powerWrapper {'pw-box-45': {'host': 'YYY', 'port': 7890, 'tags': ['ABC']}}

Your problem statement is a little on the vague side. Once you have the tags in hand, it's not clear to me what you'd want to do with them. For (2.), a list comprehension with nested for loops should suffice, using the generator I supplied.

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