Search code examples
ansiblejinja2

Match name: of the list1 to a name: of the list2 and get matches from the list2


I am trying to find matches based on list1 name: in list2, but as the result get the dict2 matches. I am using this with Ansible.

list1 :
  - name: game1
  - name: game3
list2:
  - name: game1
    type: application
    version: 123
    notes:
      type: url
      name: URLNAME
      page: https://urlname.com
  - name: game2
    type: application
    version: 223
    notes:
      type: url
      name: URLNAME
      page: https://urlname.com
  - name: game3
    type: application
    version: 333
    notes:
      type: url
      name: URLNAME
      page: https://urlname.com
  - name: game4
    type: application
    version: 443
    notes:
      type: url
      name: URLNAME
      page: https://urlname.com

Expected results:

results:
  - name: game1
    type: application
    version: 123
    notes:
      type: url
      name: URLNAME
      page: https://urlname.com
  - name: game3
    type: application
    version: 333
    notes:
      type: url
      name: URLNAME
      page: https://urlname.com

Or if it is easier, this result would suffice:

results:
  - name: game1
    type: application
    version: 123
  - name: game3
    type: application
    version: 333

This doesn't seem as a complex thing based on what I have googled and what people are trying to accomplish, but I am stuck.


Solution

    • Get the list of names. Then, selectattr test name in names
      names: "{{ list1|map(attribute='name') }}"
      results: "{{ list2|selectattr('name', 'in', names) }}"
    

    gives

      results:
        - name: game1
          notes: {name: URLNAME, page: 'https://urlname.com', type: url}
          type: application
          version: 123
        - name: game3
          notes: {name: URLNAME, page: 'https://urlname.com', type: url}
          type: application
          version: 333
    

    Example of a complete playbook for testing

    - hosts: all
    
      vars:
    
        list1:
          - name: game1
          - name: game3
        list2:
          - name: game1
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 123
          - name: game2
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 223
          - name: game3
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 333
          - name: game4
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 443
    
        names: "{{ list1|map(attribute='name') }}"
        results: "{{ list2|selectattr('name', 'in', names) }}"
    
      tasks:
    
        - debug:
            var: results|to_yaml
    

    Depending on the use case, there are many other options:

    • Convert the list to a dictionary
      names: "{{ list2|map(attribute='name') }}"
      dict2: "{{ dict(names|zip(list2)) }}"
    

    gives

      dict2:
        game1:
          name: game1
          notes: {name: URLNAME, page: 'https://urlname.com', type: url}
          type: application
          version: 123
        game2:
          name: game2
          notes: {name: URLNAME, page: 'https://urlname.com', type: url}
          type: application
          version: 223
        game3:
          name: game3
          notes: {name: URLNAME, page: 'https://urlname.com', type: url}
          type: application
          version: 333
        game4:
          name: game4
          notes: {name: URLNAME, page: 'https://urlname.com', type: url}
          type: application
          version: 443
    

    Now, you can get the same results

      results: "{{ list1|map(attribute='name')|map('extract', dict2) }}"
    

    , or easily iterate the list

        - debug:
            msg: "{{ dict2[item.name] }}"
          loop: "{{ list1 }}"
    

    gives

    ok: [test_01] => (item={'name': 'game1'}) => 
      msg:
        name: game1
        notes:
          name: URLNAME
          page: https://urlname.com
          type: url
        type: application
        version: 123
    ok: [test_01] => (item={'name': 'game3'}) => 
      msg:
        name: game3
        notes:
          name: URLNAME
          page: https://urlname.com
          type: url
        type: application
        version: 333
    

    Example of a complete playbook for testing

    - hosts: all
    
      vars:
    
        list1:
          - name: game1
          - name: game3
        list2:
          - name: game1
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 123
          - name: game2
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 223
          - name: game3
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 333
          - name: game4
            notes: {name: URLNAME, page: 'https://urlname.com', type: url}
            type: application
            version: 443
    
        names: "{{ list2|map(attribute='name') }}"
        dict2: "{{ dict(names|zip(list2)) }}"
        results: "{{ list1|map(attribute='name')|map('extract', dict2) }}"
    
      tasks:
    
        - debug:
            var: dict2|to_yaml
    
        - debug:
            var: results|to_yaml
    
        - debug:
            msg: "{{ dict2[item.name] }}"
          loop: "{{ list1 }}"