比较字典列表并合并到一个python

时间:2019-05-02 13:05:59

标签: python python-3.x dictionary

我正在编写一个python程序,将相似的字典合并为一个。我有两个字典的清单。我有一个空的filter_cache字典。我有input_completed =false变量。我将使用for循环获取字典。输入第一个字典后,将对其进行处理并将其合并为一个,然后将结果分配给filter_cache字典。通过for循环输入的列表中的下一个字典,将对其进行处理并将其合并为一个。之后,由于input_completed为空,我将true更改为data。接下来,我要比较filter_cache和当前filter_cache中的上一个字典,然后使用某些功能再次将其组合并分配给fiter_cache。如何使其成为可能

代码如下:

from itertools import groupby

field_to_be_check = "state"
merger = ["city", "haps"]
merge_name = ["cities", "my_haps"]

data = [
[{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad1', 'city': 'tenkasi'},
{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad4', 'city': 'nagerkoil'},
{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad1', 'city': 'tuticorin'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'kolikodu'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'kottayam'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'idukki'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Akola'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Washim'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Jalna'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Latur'}],
[{'haps': 'hap1', 'state': 'tamil nadu','ads': 'ad1', 'city': 'madurai'},
{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad1', 'city': 'chennai'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'palakad'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'guruvayor'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Nanded'},
]
]


input_completed = False
filter_cache = {}
for datas in data:
    #Function to make the merger lists
    def process_group(group, merger_item):

        item_set = set()
        item_list = []
        for item in group:
            item_set.add(item[merger_item])

        for item in item_set:
            item_list.append({merger_item: item})

        return item_list

    #Group on haps, state and ads
    grp = groupby(datas,key=lambda x:(x[field_to_be_check]))
    result = []

    #Iterate through the group and build your result list
    for model, group in grp:
        cities_dict = {}

        cities_dict[field_to_be_check] = model

        group_list = list(group)

        #Make the list for merger fields
        for idx, name in enumerate(merger):
            cities_dict[merge_name[idx]] = process_group(group_list, name)

        result.append(cities_dict)
        filter_cache.update({'aggregate':result})
    print(filter_cache)


    final_result = filter_cache

我得到的输出:

{'aggregate': [{'state': 'tamil nadu', 'my_haps': [{'haps': 'hap0'}], 'cities': [{'city': 'tuticorin'}, {'city': 'tenkasi'}, {'city': 'nagerkoil'}]}, {'state': 'kerala', 'my_haps': [{'haps': 'hap1'}], 'cities': [{'city': 'idukki'}, {'city': 'kolikodu'}, {'city': 'kottayam'}]}, {'state': 'mumbai', 'my_haps': [{'haps': 'hap2'}], 'cities': [{'city': 'Akola'}, {'city': 'Jalna'}, {'city': 'Latur'}, {'city': 'Washim'}]}]}
{'aggregate': [{'state': 'tamil nadu', 'my_haps': [{'haps': 'hap1'}, {'haps': 'hap0'}], 'cities': [{'city': 'madurai'}, {'city': 'chennai'}]}, {'state': 'kerala', 'my_haps': [{'haps': 'hap1'}], 'cities': [{'city': 'palakad'}, {'city': 'guruvayor'}]}, {'state': 'mumbai', 'my_haps': [{'haps': 'hap2'}], 'cities': [{'city': 'Nanded'}]}]}

必需的输出:

{'aggregate': [{'state': 'tamil nadu', 'my_haps': [{'haps': 'hap0'},{'haps': 'hap1'}], 'cities': [{'city': 'tuticorin'}, {'city': 'tenkasi'}, {'city': 'nagerkoil'},{'city': 'madurai'}, {'city': 'chennai'}]}, {'state': 'kerala', 'my_haps': [{'haps': 'hap1'}], 'cities': [{'city': 'idukki'}, {'city': 'kolikodu'}, {'city': 'kottayam'},{'city': 'palakad'}, {'city': 'guruvayor'}]}, {'state': 'mumbai', 'my_haps': [{'haps': 'hap2'}], 'cities': [{'city': 'Akola'}, {'city': 'Jalna'}, {'city': 'Latur'}, {'city': 'Washim'},{'city': 'Nanded'}]}]}

2 个答案:

答案 0 :(得分:1)

功能

def group_dicts_from_list(lst, group_by, merge_rules, result):
    if not lst or not isinstance(lst, list) or not group_by or not merge_rules or \
            not isinstance(merge_rules, dict) or not isinstance(result, dict):
        return
    if "aggregate" not in result:
        result["aggregate"] = []
    for item in lst:
        if isinstance(item, dict):
            if group_by in item:
                for res in result["aggregate"]:
                    if res[group_by] == item[group_by]:
                        tmp = res
                        break
                else:
                    tmp = {group_by: item[group_by]}
                    result["aggregate"].append(tmp)
                for src, dst in merge_rules.items():
                    if src in item:
                        if dst not in tmp:
                            tmp[dst] = []
                        src_tmp = {src: item[src]}
                        if src_tmp not in tmp[dst]:
                            tmp[dst].append(src_tmp)
        elif isinstance(item, list):
            group_dicts_from_list(item, group_by, merge_rules, result) # !!! recursion !!! 

用法:

field_to_be_check = "state"
my_merge_rules = {
    "city": "cities",
    "haps": "my_haps",
}
data = [
    [{'haps': 'hap0', 'state': 'tamil nadu', 'ads': 'ad1', 'city': 'tenkasi'},
     {'haps': 'hap0', 'state': 'tamil nadu', 'ads': 'ad4', 'city': 'nagerkoil'},
     {'haps': 'hap0', 'state': 'tamil nadu', 'ads': 'ad1', 'city': 'tuticorin'},
     {'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'kolikodu'},
     {'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'kottayam'},
     {'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'idukki'},
     {'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Akola'},
     {'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Washim'},
     {'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Jalna'},
     {'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Latur'}],
    [{'haps': 'hap1', 'state': 'tamil nadu', 'ads': 'ad1', 'city': 'madurai'},
     {'haps': 'hap0', 'state': 'tamil nadu', 'ads': 'ad1', 'city': 'chennai'},
     {'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'palakad'},
     {'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'guruvayor'},
     {'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Nanded'},
     ]
]

result = {}
group_dicts_from_list(data, field_to_be_check, my_merge_rules, result)

print(result)

输出:

{'aggregate': [{'state': 'tamil nadu', 'cities': [{'city': 'tenkasi'}, {'city': 'nagerkoil'}, {'city': 'tuticorin'}, {'city': 'madurai'}, {'city': 'chennai'}], 'my_haps': [{'haps': 'hap0'}, {'haps': 'hap1'}]}, {'state': 'kerala', 'cities': [{'city': 'kolikodu'}, {'city': 'kottayam'}, {'city': 'idukki'}, {'city': 'palakad'}, {'city': 'guruvayor'}], 'my_haps': [{'haps': 'hap1'}]}, {'state': 'mumbai', 'cities': [{'city': 'Akola'}, {'city': 'Washim'}, {'city': 'Jalna'}, {'city': 'Latur'}, {'city': 'Nanded'}], 'my_haps': [{'haps': 'hap2'}]}]}

评论:

我已替换

merger = ["city", "haps"]
merge_name = ["cities", "my_haps"]

使用

my_merge_rules = {
    "city": "cities",
    "haps": "my_haps",
}

因为我发现它更可靠(它可以防止列表长度不同的情况出现)

答案 1 :(得分:0)

您的代码和可接受的答案对我来说似乎过于复杂(也许我不理解要求)。为什么不建立字典:field_to_be_check -> merger_name -> merger values,然后将其转换为所需的格式?

创建字典:

import itertools

data = [[{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad1', 'city': 'tenkasi'},
{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad4', 'city': 'nagerkoil'},
{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad1', 'city': 'tuticorin'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'kolikodu'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'kottayam'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'idukki'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Akola'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Washim'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Jalna'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Latur'}],
[{'haps': 'hap1', 'state': 'tamil nadu','ads': 'ad1', 'city': 'madurai'},
{'haps': 'hap0', 'state': 'tamil nadu','ads': 'ad1', 'city': 'chennai'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'palakad'},
{'haps': 'hap1', 'state': 'kerala', 'ads': 'ad2', 'city': 'guruvayor'},
{'haps': 'hap2', 'state': 'mumbai', 'ads': 'ad3', 'city': 'Nanded'},]]

field_to_be_check = "state"
name_by_merger = {"city": "cities", "haps": "my_haps"}

d = {}
for row in itertools.chain(*data):
    inner_d = d.setdefault(row[field_to_be_check], {})
    for m, n in name_by_merger.items():
        inner_d.setdefault(n, set()).add(row[m])

d的内容:

{'tamil nadu': {'cities': {'chennai', 'nagerkoil', 'tuticorin', 'madurai', 'tenkasi'}, 'my_haps': {'hap0', 'hap1'}}, 'kerala': {'cities': {'kolikodu', 'palakad', 'idukki', 'guruvayor', 'kottayam'}, 'my_haps': {'hap1'}}, 'mumbai': {'cities': {'Nanded', 'Latur', 'Jalna', 'Akola', 'Washim'}, 'my_haps': {'hap2'}}}

函数itertools.chain将两个列表合并。如果需要,setdefault方法会在字典中创建一个新条目。

转换为所需格式仅是(很丑陋的)dict理解:

{'aggregate': [{field_to_be_check: k, **{n: [{m: x} for x in v[n]] for m, n in name_by_merger.items()}} for k, v in d.items()]}

输出:

{'aggregate': [{'state': 'tamil nadu', 'cities': [{'city': 'chennai'}, {'city': 'nagerkoil'}, {'city': 'tuticorin'}, {'city': 'madurai'}, {'city': 'tenkasi'}], 'my_haps': [{'haps': 'hap0'}, {'haps': 'hap1'}]}, {'state': 'kerala', 'cities': [{'city': 'kolikodu'}, {'city': 'palakad'}, {'city': 'idukki'}, {'city': 'guruvayor'}, {'city': 'kottayam'}], 'my_haps': [{'haps': 'hap1'}]}, {'state': 'mumbai', 'cities': [{'city': 'Nanded'}, {'city': 'Latur'}, {'city': 'Jalna'}, {'city': 'Akola'}, {'city': 'Washim'}], 'my_haps': [{'haps': 'hap2'}]}]}

当然,您可以通过一次构建所需的输出,但是由于格式繁琐,我认为先创建一个nive词典然后遵循该格式比较干净。