Python 在Ansible字典中查找重复项

Python 在Ansible字典中查找重复项,python,ansible,jinja2,Python,Ansible,Jinja2,我需要检查两个子字典中是否没有使用相同的端口 my_dict: first: redis: port: 1234 second: redis: port: 1235 third: redis: port: 1234 在任务中,我可以使用以下各项: - debug: msg: '{{ my_dict | dict2items | map(attribute="value.redis.port") | list }}'

我需要检查两个子字典中是否没有使用相同的端口

my_dict:
  first:
    redis:
      port: 1234
  second:
    redis:
      port: 1235
  third:
    redis:
      port: 1234
在任务中,我可以使用以下各项:

- debug:
    msg: '{{ my_dict | dict2items | map(attribute="value.redis.port") | list }}'
这将返回:

['1234', '1235', '1234']
我需要的是某种只过滤重复项的方法。所以我得到:

['1234', '1234']
返回

基本上,我需要检查端口是否重复,如果重复,则应用一个失败任务来检查并显示哪些项导致了冲突


有什么想法吗?

在这种特定情况下,@stacksonstacks链接到的过滤器没有帮助,因为端口的数量总是相同的,只是它们的数量发生了变化:
set([1,2,2])==set([1,2])
总是
True

因此,我们真正想要的是按端口分组,并查找长度大于1的子级。然后,我们可以提取导致冲突的密钥的名称,以便报告冲突

tasks:
- set_fact:
    bogus: >-
      {%- for port_num, dicts in (my_dict | dict2items | groupby('value.redis.port'))
          if (dicts|length) > 1 -%}
      {{ dicts | map(attribute='key') | list }}
      {%- endfor -%}

- debug: var=item
  when: '{{ (bogus | length) > 0 }}'
  with_items: '{{ bogus }}'

非常感谢你的帮助,马修

我觉得有点太难看了,到处都是事实等等,所以我决定快速制作一个过滤器插件。。。或者更重要的是,对文件进行添加

添加:

def duplicate(a):
    if isinstance(a, collections.Hashable):
        c = set(a)
    else:
        s = {}
        c = []

        for x in a:
            if x not in s:
                s[x] = 1
            else:
                if s[x] == 1:
                    c.append(x)
                s[x] += 1
    return c
在文件正文中,添加:

'duplicate': duplicate,
关于:

class FilterModule(object):
    ''' Ansible math jinja2 filters '''

    def filters(self):
        filters = {
因此,
Jinja2
了解过滤器

当我有时间的时候,我会提出一个请求,但是如果有人同时发现了这个问题,或者如果你不想/不能更新Ansible,那么下面的方法非常有效:

- debug:
    msg: '{{ my_dict | dict2items | map(attribute="value.redis.port") | list | duplicate }}'
返回:

['1234']
我已经用更大的样本运行了一些测试,并且它按照预期工作


享受吧

我没有看到其中一个只显示重复项。非常感谢。。。但是很快,你能解释一下为什么:
{my_dict | dict2items | map(attribute=“value.redis.port”)| list | dict | dict2items | map(attribute=“value.redis.port”)| list | unique}
不起作用吗?你完全正确,很抱歉,我一开始没有看到这个“bug”。我已经更新了我的答案,并提供了一个解释,以及一个大大缩短的事实设置。此代码仅适用于单个重复元素(请参见在源数据中添加端口为1235的
第四个
元素时发生的情况)。然而,出于我无法理解的原因,在循环中的元素之间加一个逗号就足够了。 ・ 如果(1)模板中有一个Jinja2 for循环,(2)Ansible调用Jinja2,并且(3)模板的结果是一个带有逗号分隔的JSON列表的字符串,那么Jinja2(或Ansible?)会生成一个元组(将整个内容封装在括号中)。