diff --git a/changelogs/fragments/72729-add-filter-duplicated.yml b/changelogs/fragments/72729-add-filter-duplicated.yml new file mode 100644 index 00000000000..949184c8e2f --- /dev/null +++ b/changelogs/fragments/72729-add-filter-duplicated.yml @@ -0,0 +1,3 @@ +minor_changes: + - add filter duplicated that will return duplicate items from a list. + (https://github.com/ansible/ansible/pull/72729/) diff --git a/docs/docsite/rst/user_guide/playbooks_filters.rst b/docs/docsite/rst/user_guide/playbooks_filters.rst index 984de55e4b3..9ea4104440a 100644 --- a/docs/docsite/rst/user_guide/playbooks_filters.rst +++ b/docs/docsite/rst/user_guide/playbooks_filters.rst @@ -978,6 +978,14 @@ To get the symmetric difference of 2 lists (items exclusive to each list):: {{ list1 | symmetric_difference(list2) }} # => [10, 11, 99] +To get the duplicate values from a list (the resulting list contains unique duplicates):: + +.. versionadded:: 2.11 + + # list1: [1, 2, 5, 1, 3, 4, 10, 'a', 'z', 'a'] + {{ list1 | duplicated }} + # => [1, 'a'] + .. _math_stuff: Calculating numbers (math) diff --git a/lib/ansible/plugins/filter/mathstuff.py b/lib/ansible/plugins/filter/mathstuff.py index 77baa7ef006..52deb37fdf8 100644 --- a/lib/ansible/plugins/filter/mathstuff.py +++ b/lib/ansible/plugins/filter/mathstuff.py @@ -26,6 +26,7 @@ __metaclass__ = type import itertools import math +from collections import Counter from jinja2.filters import environmentfilter from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError @@ -86,6 +87,11 @@ def unique(environment, a, case_sensitive=False, attribute=None): return c +@environmentfilter +def duplicated(environment, a): + return [k for k, v in Counter(a).items() if v > 1] + + @environmentfilter def intersect(environment, a, b): if isinstance(a, Hashable) and isinstance(b, Hashable): @@ -257,6 +263,7 @@ class FilterModule(object): # set theory 'unique': unique, + 'duplicated': duplicated, 'intersect': intersect, 'difference': difference, 'symmetric_difference': symmetric_difference, diff --git a/test/units/plugins/filter/test_mathstuff.py b/test/units/plugins/filter/test_mathstuff.py index d44a7146699..ec4d5be034e 100644 --- a/test/units/plugins/filter/test_mathstuff.py +++ b/test/units/plugins/filter/test_mathstuff.py @@ -180,3 +180,11 @@ class TestRekeyOnMember(): list_original = ({'proto': 'eigrp', 'id': 1}, {'proto': 'ospf', 'id': 2}, {'proto': 'eigrp', 'id': 3}) expected = {'eigrp': {'proto': 'eigrp', 'id': 3}, 'ospf': {'proto': 'ospf', 'id': 2}} assert ms.rekey_on_member(list_original, 'proto', duplicates='overwrite') == expected + + +class TestDuplicated: + def test_empty(self): + assert ms.duplicated(env, []) == [] + + def test_numbers(self): + assert ms.duplicated(env, [1, 3, 5, 5]) == [5]