Kiran Kumar H N
Kiran Kumar H N

Reputation: 101

Ansible: Merge 2 lists using common key

I have a use case where I need to merge 2 lists on common key name using Ansible.

List1:

 {
        "poc-cu2": [
            "40:A6:B7:5E:22:11",
            "40:A6:B7:5E:22:22"
        ],
        "test2211": [
            "40:A6:B7:5E:33:11",
            "40:A6:B7:5E:33:22"
        ],
        "test2244": [
            "40:A6:B7:5E:22:45",
            "40:A6:B7:5E:22:46"
        ]
    }

List2:

{
        "poc-cu2": [
            "root",
            "9WKA3KK3XN39",
            "9.3.13.44"
        ],
        "test2211": [
            "root2211",
            "221122112211",
            "9.3.13.82"
        ]
    }

Expected:

List3:

{
        "poc-cu2": [
            "root",
            "9WKA3KK3XN39",
            "9.3.13.44",
            "40:A6:B7:5E:22:11",
            "40:A6:B7:5E:22:22"
        ],
        "test2211": [
            "root2211",
            "221122112211",
            "9.3.13.82",
            "40:A6:B7:5E:33:11",
            "40:A6:B7:5E:33:22"
        ]
    }

I got how to merge 2 lists using unique key but on my case I need to merge only on common key, please suggest.

Upvotes: 1

Views: 1144

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 67984

Given the data

    dict1:
      poc-cu2:
        - 40:A6:B7:5E:22:11
        - 40:A6:B7:5E:22:22
      test2211:
        - 40:A6:B7:5E:33:11
        - 40:A6:B7:5E:33:22
      test2244:
        - 40:A6:B7:5E:22:45
        - 40:A6:B7:5E:22:46

    dict2:
      poc-cu2:
        - root
        - 9WKA3KK3XN39
        - 9.3.13.44
      test2211:
        - root2211
        - '221122112211'
        - 9.3.13.82

Iteration is not needed. Put the declarations below as appropriate. The dictionary dict_cmn keeps the merged common attributes of dict1 and dict2

dict_1_2: "{{ dict1|combine(dict2, list_merge='append') }}"
keys_cmn: "{{ dict1.keys()|intersect(dict2.keys()) }}"
vals_cmn: "{{ keys_cmn|map('extract', dict_1_2) }}"
dict_cmn: "{{ dict(keys_cmn|zip(vals_cmn)) }}"

give

  dict_1_2:
    poc-cu2:
    - 40:A6:B7:5E:22:11
    - 40:A6:B7:5E:22:22
    - root
    - 9WKA3KK3XN39
    - 9.3.13.44
    test2211:
    - 40:A6:B7:5E:33:11
    - 40:A6:B7:5E:33:22
    - root2211
    - '221122112211'
    - 9.3.13.82
    test2244:
    - 40:A6:B7:5E:22:45
    - 40:A6:B7:5E:22:46

  keys_cmn:
  - poc-cu2
  - test2211

  vals_cmn:
  - - 40:A6:B7:5E:22:11
    - 40:A6:B7:5E:22:22
    - root
    - 9WKA3KK3XN39
    - 9.3.13.44
  - - 40:A6:B7:5E:33:11
    - 40:A6:B7:5E:33:22
    - root2211
    - '221122112211'
    - 9.3.13.82

  dict_cmn:
    poc-cu2:
    - 40:A6:B7:5E:22:11
    - 40:A6:B7:5E:22:22
    - root
    - 9WKA3KK3XN39
    - 9.3.13.44
    test2211:
    - 40:A6:B7:5E:33:11
    - 40:A6:B7:5E:33:22
    - root2211
    - '221122112211'
    - 9.3.13.82

Upvotes: 0

larsks
larsks

Reputation: 311268

You can get most of what you want using the combine filter, like this:

- hosts: localhost
  gather_facts: false
  tasks:
    - set_fact:
        dict3: "{{ dict1|combine(dict2, list_merge='append') }}"

    - debug:
        var: dict3

This will produce:

TASK [debug] *******************************************************************
ok: [localhost] => {
    "dict3": {
        "poc-cu2": [
            "40:A6:B7:5E:22:11",
            "40:A6:B7:5E:22:22",
            "root",
            "9WKA3KK3XN39",
            "9.3.13.44"
        ],
        "test2211": [
            "40:A6:B7:5E:33:11",
            "40:A6:B7:5E:33:22",
            "root2211",
            "221122112211",
            "9.3.13.82"
        ],
        "test2244": [
            "40:A6:B7:5E:22:45",
            "40:A6:B7:5E:22:46"
        ]
    }
}

If you want the final result to consist of only the keys common to both dictionaries it gets a little trickier, but this seems to work:

- hosts: localhost
  gather_facts: false
  tasks:
    - set_fact:
        dict3: "{{ dict3|combine({item: dict1[item] + dict2[item]}) }}"
      when: item in dict2
      loop: "{{ dict1.keys() }}"
      vars:
        dict3: {}

    - debug:
        var: dict3

Which produces:

TASK [debug] *******************************************************************
ok: [localhost] => {
    "dict3": {
        "poc-cu2": [
            "40:A6:B7:5E:22:11",
            "40:A6:B7:5E:22:22",
            "root",
            "9WKA3KK3XN39",
            "9.3.13.44"
        ],
        "test2211": [
            "40:A6:B7:5E:33:11",
            "40:A6:B7:5E:33:22",
            "root2211",
            "221122112211",
            "9.3.13.82"
        ]
    }
}

The above works by iterating over the keys in dict1, and for each key from dict1 that also exists in dict2, we synthesize a new dictionary containing the corresponding values from both dict1 and dict2 and then merge it into our final dictionary using the combine filter.

Upvotes: 2

Related Questions