Repository: ansible-collections/community.general

Issue:
New merge lists plugin from a given key
<!--- Verify first that your feature was not already discussed on GitHub -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
<!--- Describe the new feature/improvement briefly below -->
Given two lists like:

```yaml
list1:
  - name: myname01
    param01: myparam01
  - name: myname02
    param01: myparam02

list2:
  - name: myname01
    param01: myparam03
  - name: myname02
    param02: myparam04
  - name: myname03
    param03: myparam03
```

When doing:

```yaml
"{{ query('mergelist', 'name', list1, list2) }}"
```

The results will be:

```yaml
  - name: myname01
    param01: myparam03
  - name: myname02
    param01: myparam02
    param02: myparam04
  - name: myname03
    param03: myparam03
```

##### ISSUE TYPE
- Feature Idea

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below, use your best guess if unsure -->
`mergelist`
##### ADDITIONAL INFORMATION
<!--- Describe how the feature would be used, why it is needed and what it would solve -->
I have already developed the solution. I really think it could be really useful in the Ansible Collections General. Please confirm.
<!--- Paste example playbooks or commands between quotes below -->
```yaml
  - name: Basic usage
    debug:
      msg: "{{ query('mergelist', 'name', list1, list2) }}"
```
<!--- HINT: You can also paste gist.github.com links for larger files -->


Discussion:
Guys, confirm if the functionality as new plugin included in this collection is feasible. I already have the functionality ready for a PR. Thanks!

Resolving patch:
diff --git a/plugins/filter/list.py b/plugins/filter/list.py
new file mode 100644
--- /dev/null
+++ b/plugins/filter/list.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Vladimir Botka <vbotka@gmail.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.errors import AnsibleError, AnsibleFilterError
+from ansible.module_utils.six import string_types
+from ansible.module_utils.common._collections_compat import Mapping, Sequence
+from collections import defaultdict
+from operator import itemgetter
+
+
+def lists_mergeby(l1, l2, index):
+    ''' merge lists by attribute index. Example:
+        - debug: msg="{{ l1|community.general.lists_mergeby(l2, 'index')|list }}" '''
+
+    if not isinstance(l1, Sequence):
+        raise AnsibleFilterError('First argument for community.general.lists_mergeby must be list. %s is %s' %
+                                 (l1, type(l1)))
+
+    if not isinstance(l2, Sequence):
+        raise AnsibleFilterError('Second argument for community.general.lists_mergeby must be list. %s is %s' %
+                                 (l2, type(l2)))
+
+    if not isinstance(index, string_types):
+        raise AnsibleFilterError('Third argument for community.general.lists_mergeby must be string. %s is %s' %
+                                 (index, type(index)))
+
+    d = defaultdict(dict)
+    for l in (l1, l2):
+        for elem in l:
+            if not isinstance(elem, Mapping):
+                raise AnsibleFilterError('Elements of list arguments for lists_mergeby must be dictionaries. Found {0!r}.'.format(elem))
+            if index in elem.keys():
+                d[elem[index]].update(elem)
+    return sorted(d.values(), key=itemgetter(index))
+
+
+class FilterModule(object):
+    ''' Ansible list filters '''
+
+    def filters(self):
+        return {
+            'lists_mergeby': lists_mergeby,
+        }


Test patch:
diff --git a/tests/integration/targets/filter_list/aliases b/tests/integration/targets/filter_list/aliases
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/filter_list/aliases
@@ -0,0 +1,2 @@
+shippable/posix/group2
+skip/python2.6  # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/tests/integration/targets/filter_list/tasks/main.yml b/tests/integration/targets/filter_list/tasks/main.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/filter_list/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- name: Test lists merged by attribute name
+  assert:
+    that:
+      - "(list1 | community.general.lists_mergeby(list2, 'name') | list |
+          difference(list3) | length) == 0"
diff --git a/tests/integration/targets/filter_list/vars/main.yml b/tests/integration/targets/filter_list/vars/main.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/filter_list/vars/main.yml
@@ -0,0 +1,22 @@
+list1:
+  - name: myname01
+    param01: myparam01
+  - name: myname02
+    param01: myparam02
+
+list2:
+  - name: myname01
+    param01: myparam03
+  - name: myname02
+    param02: myparam04
+  - name: myname03
+    param03: myparam03
+
+list3:
+  - name: myname01
+    param01: myparam03
+  - name: myname02
+    param01: myparam02
+    param02: myparam04
+  - name: myname03
+    param03: myparam03