Ansible根据键获取唯一的字典列表
Ansible get unique list of dictionaries based on a key
我有两个列表:
list1: [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
list2: [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
我需要派生另一个列表,list3
,它应该包含 list1
中不存在的元素 list2
基于键 - id
's值。
我试过使用 jinja2 但没有得到想要的输出。
剧本:
- name: test
hosts: localhost
connection: local
vars:
- list1: [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
- list2: [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
gather_facts: False
tasks:
- set_fact:
list3: |-
{%- set dL = [] -%}
{%- for i in list1 -%}
{%- for j in list2 -%}
{%- if (i['id'] != j['id']) and (i not in dL) -%}
{{- dL.append(i) -}}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
{{- dL -}}
- debug: var=list3
输出:
"list3": [
{
"a": "name1",
"id": "ABC"
},
{
"ax": "name2",
"id": "DEF"
}
]
预期输出:
"list3": [
{
"a": "name1",
"id": "ABC"
}
]
我怎样才能达到这个结果?
像这样使用列表理解:
list1 = [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
list2 = [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
key = 'id'
l2vals = [d[key] for d in list2]
list3 = [d for d in list1 if d[key] not in l2vals]
print(list3)
输出:
[{'a': 'name1', 'id': 'ABC'}]
您可以使用 rejectattr
in order to reject all the id
contained in a list populated from list2
. This later list can be created using map
从 list2
中仅提取 id
。
所有这一切一起完成了这个简单的任务:
- set_fact:
list3: "{{ list1 | rejectattr('id', 'in', list2 | map(attribute='id')) }}"
鉴于剧本:
- hosts: localhost
gather_facts: no
tasks:
- set_fact:
list3: "{{ list1 | rejectattr('id', 'in', list2 | map(attribute='id')) }}"
vars:
list1: [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
list2: [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
- debug:
var: list3
这产生:
TASK [set_fact] ********************************************************
ok: [localhost]
TASK [debug] ***********************************************************
ok: [localhost] => {
"list3": [
{
"a": "name1",
"id": "ABC"
}
]
}
我有两个列表:
list1: [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
list2: [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
我需要派生另一个列表,list3
,它应该包含 list1
中不存在的元素 list2
基于键 - id
's值。
我试过使用 jinja2 但没有得到想要的输出。
剧本:
- name: test
hosts: localhost
connection: local
vars:
- list1: [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
- list2: [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
gather_facts: False
tasks:
- set_fact:
list3: |-
{%- set dL = [] -%}
{%- for i in list1 -%}
{%- for j in list2 -%}
{%- if (i['id'] != j['id']) and (i not in dL) -%}
{{- dL.append(i) -}}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
{{- dL -}}
- debug: var=list3
输出:
"list3": [
{
"a": "name1",
"id": "ABC"
},
{
"ax": "name2",
"id": "DEF"
}
]
预期输出:
"list3": [
{
"a": "name1",
"id": "ABC"
}
]
我怎样才能达到这个结果?
像这样使用列表理解:
list1 = [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
list2 = [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
key = 'id'
l2vals = [d[key] for d in list2]
list3 = [d for d in list1 if d[key] not in l2vals]
print(list3)
输出:
[{'a': 'name1', 'id': 'ABC'}]
您可以使用 rejectattr
in order to reject all the id
contained in a list populated from list2
. This later list can be created using map
从 list2
中仅提取 id
。
所有这一切一起完成了这个简单的任务:
- set_fact:
list3: "{{ list1 | rejectattr('id', 'in', list2 | map(attribute='id')) }}"
鉴于剧本:
- hosts: localhost
gather_facts: no
tasks:
- set_fact:
list3: "{{ list1 | rejectattr('id', 'in', list2 | map(attribute='id')) }}"
vars:
list1: [ {'a': 'name1', 'id': 'ABC'}, {'ax': 'name2', 'id': 'DEF'} ]
list2: [ {'a': 'nameX', 'id': 'XYZ'}, {'ab': 'nameY', 'id': 'DEF'} ]
- debug:
var: list3
这产生:
TASK [set_fact] ********************************************************
ok: [localhost]
TASK [debug] ***********************************************************
ok: [localhost] => {
"list3": [
{
"a": "name1",
"id": "ABC"
}
]
}