Iterating over parts complex data structures while still referring to other parts of the structure

I have a data structure like this:

`
part:
eyes:
where: faces
colors:

  • blue
  • brown
  • green
    hair:
    where: heads
    colors:
  • black
  • blond
  • brown
  • red
    toenails:
    where: feet
    colors:
  • pink
  • red
  • teal
    `

I want to create a file for each of the colors in the nested lists, with a name like /etc/parts/eyes_blue, and in that template, have things like “This is the file about things with blue eyes on their faces” or “This is the file about things with red toenails on their feet” (in /etc/parts/toenails_red). So I don’t want to loop over the part dict, or the various dicts in the part dict, but over the colors lists – but I need to do that while also keeping track of where in the data structure I am, so I don’t want to just flatten them into one big list and iterate over it. If I were writing code for this, I’d do something like

`
for (key, value) in part.items():
for color in value[‘colors’]:
with open (“foodir/{}_{}”.format(key, color), ‘w’) as fh:
fh.write(“This is the file about things with {} {} on their {}”.format(color, key, value[‘where’]))

`

Is there a way to do that in an Ansible task somehow?

It would be easier to rewrite your var to something like:

part:

  • name: eyes
    where: faces
    colors:
  • blue
  • brown
  • green

And then use:

  • debug:
    msg: “{{ item.0.name }}{{ item.1 }}"
    loop: “{{ part|subelements(‘colors’) }}”
    loop_control:
    label: "{{ item.0.name }}
    {{ item.1 }}”

Otherwise, using your current data structure:

  • debug:
    msg: “{{ item.0.0 }}{{ item.1 }}"
    loop: “{{ part|dictsort|subelements([1, ‘colors’]) }}”
    loop_control:
    label: "{{ item.0.0 }}
    {{ item.1 }}”

From there, you should be able to extrapolate to meet your specific needs, potentially using the template module, to write out the files.

Awesome, that works (with my var as-is – it’d be a pain to rewrite it) – thanks!

Unfortunately, (a) it’s actually even more complicated than that, I forgot a level; and (b) I’m having a hard time figuring out exactly how subelements works to extend this myself. :^p

If you don’t mind a stupid follow-up, what would it look like if the data structure was actually more like this:

`
part:
human:
eyes:
where: faces
colors:

  • blue
  • brown
  • green
    hair:
    where: heads
    colors:
  • black
  • blond
  • brown
  • red
    toenails:
    where: feet
    colors:
  • pink
  • red
  • teal
    slugs:
    eyes:
    where: antennae
    colors:
  • brown
  • black

`

Your solution works perfectly if I send it part[‘human’], but I’d love to be able to send it just ‘part’, and get both humans and slugs. I tried some naive stuff with adding more .0 type things, but couldn’t figure it out. :^(