Python:在键相同的字典列表中组合唯一值?

时间:2021-01-12 14:33:01

标签: python python-3.x list dictionary-comprehension

我不确定我的提问方式是否正确,但这是我的问题:

我有以下格式的字典列表:

[
{'user': 'joe', 'IndexUsed': 'a'}, 
{'user': 'joe', 'IndexUsed': 'a'},
{'user': 'joe', 'IndexUsed': 'a'},
{'user': 'joe', 'IndexUsed': 'b'}, 
{'user': 'admin', 'IndexUsed': 'a'}, 
{'user': 'admin', 'IndexUsed': 'c'},
{'user': 'hugo', 'IndexUsed': 'a'},
{'user': 'hugo', 'IndexUsed': 'd'},
...
]

我希望我的最终结果如下所示:

[
{'user': 'joe', 'IndexUsed': ['a', 'b']}, 
{'user': 'admin', 'IndexUsed': ['a', 'c']}, 
{'user': 'hugo', 'IndexUsed': ['a', 'd']},
]

本质上,将 IndexUsed 中的唯一字段组合/重复数据删除,并将它们减少到每个 user 仅一个 dict

我研究过使用 reducer、dict 理解并在 StackOverflow 上进行搜索,但我在使用字符串查找用例时遇到了一些麻烦。我发现的大多数示例都使用整数将它们组合成最终的 int/float,但在这里我更愿意将它组合成一个最终的字符串。你能帮我理解如何解决这个问题吗?

4 个答案:

答案 0 :(得分:4)

from collections import defaultdict


data = [{'IndexUsed': 'a', 'user': 'joe'},
 {'IndexUsed': 'a', 'user': 'joe'},
 {'IndexUsed': 'a', 'user': 'joe'},
 {'IndexUsed': 'b', 'user': 'joe'},
 {'IndexUsed': 'a', 'user': 'admin'},
 {'IndexUsed': 'c', 'user': 'admin'},
 {'IndexUsed': 'a', 'user': 'hugo'},
 {'IndexUsed': 'd', 'user': 'hugo'}]

indexes_used = defaultdict(set)
for d in data:
    indexes_used[d['user']].add(d['IndexUsed'])

result = []
for k, v in indexes_used.items():
    result.append({'user': k, 'IndexUsed': sorted(list(v))})

print(*result)

输出:

{'user': 'joe', 'IndexUsed': ['a', 'b']} {'user': 'admin', 'IndexUsed': ['a', 'c']} {'user': 'hugo', 'IndexUsed': ['a', 'd']}

注意:对于不知情的人,defaultdict 使用传递的函数(在本例中为set)作为工厂来创建新的缺失键对应值。所以 indexes_used 的每一个键都被设置为 一个 set 填充了使用过的索引。使用 set 也会忽略重复项。最后,set 被转换为排序列表,同时创建所需的键 IndexUsed

答案 1 :(得分:1)

如果保证字典按名称分组在一起,那么您可以使用 itertools.groupby 分别处理每组字典:

from itertools import groupby
from operator import itemgetter

data = [
    {'user': 'joe', 'IndexUsed': 'a'},
    {'user': 'joe', 'IndexUsed': 'a'},
    {'user': 'joe', 'IndexUsed': 'a'},
    {'user': 'joe', 'IndexUsed': 'b'},
    {'user': 'admin', 'IndexUsed': 'a'},
    {'user': 'admin', 'IndexUsed': 'c'},
    {'user': 'hugo', 'IndexUsed': 'a'},
    {'user': 'hugo', 'IndexUsed': 'd'},
]

merged_data = [{"user": key, "IndexUsed": list({i: None for i in map(itemgetter("IndexUsed"), group)})} for key, group in groupby(data, key=itemgetter("user"))]
for d in merged_data:
    print(d)

输出:

{'user': 'joe', 'IndexUsed': ['a', 'b']}
{'user': 'admin', 'IndexUsed': ['a', 'c']}
{'user': 'hugo', 'IndexUsed': ['a', 'd']}
>>> 

这只是我想到的第一件事,但我不喜欢它有几个原因。首先,就像我说的那样,它假设原始字典是通过键 user 组合在一起的。此外,长列表推导式不可读,应避免使用。生成合并的 IndexUsed 列表的方式是创建一个临时字典,将唯一条目映射到 None(ew,gross - 使用字典而不是集合,因为集合不保留插入顺序)。它还假设您使用的是 Python 3.x+ 的某个版本,其中字典保证保留插入顺序(您可以使用 collections.OrderedDict 更明确,但这是另一个导入)。最后,您不必对 "user""IndexUsed" 键字面量进行硬编码。有人请提出更好的答案。

答案 2 :(得分:1)

如果您有兴趣,一种无需使用任何库即可满足此要求的方法:

arr = [
{'user': 'joe', 'IndexUsed': 'a'}, 
{'user': 'joe', 'IndexUsed': 'a'},
{'user': 'joe', 'IndexUsed': 'a'},
{'user': 'joe', 'IndexUsed': 'b'}, 
{'user': 'admin', 'IndexUsed': 'a'}, 
{'user': 'admin', 'IndexUsed': 'c'},
{'user': 'hugo', 'IndexUsed': 'a'},
{'user': 'hugo', 'IndexUsed': 'd'},
]

global_dict = {}


            
for d in arr:


     if(False if d["user"] in global_dict else True):

            global_dict[d["user"]] = [d["IndexUsed"]]
     else:
            global_dict[d["user"]].append(d["IndexUsed"])
            global_dict[d["user"]] = list(set(global_dict[d["user"]]))
 

print(global_dict)

# Now we get a dict of dicts with key as user and value as an array of distinct IndexUsed values: 
# {
#  'joe': ['b', 'a'],
#  'admin': ['c', 'a'],
#  'hugo': ['d', 'a']
# }



final_list = []

for k,v in global_dict.items():
    final_list.append({"user":k,"IndexUsed":v})


print(final_list)

#Desired Output
# [
#  {'user': 'joe', 'IndexUsed': ['b', 'a']},
#  {'user': 'admin', 'IndexUsed': ['c', 'a']},
#  {'user': 'hugo', 'IndexUsed': ['d', 'a']}
# ]

但是,如果您是短线的粉丝... 让我尽量减少@progmatico 对这三行的出色 defaultdict 方法。

from collections import defaultdict


indexes_used = defaultdict(set)
[indexes_used[d['user']].add(d['IndexUsed']) for d in data] # for the side effect
print([{'user': k, 'IndexUsed': sorted(list(v))} for k, v in indexes_used.items()])

它仍然可读。

答案 3 :(得分:0)

没有任何外部库:

l = [
    {'user': 'joe', 'IndexUsed': 'a'}, 
    {'user': 'joe', 'IndexUsed': 'a'},
    {'user': 'joe', 'IndexUsed': 'a'},
    {'user': 'joe', 'IndexUsed': 'b'}, 
    {'user': 'admin', 'IndexUsed': 'a'}, 
    {'user': 'admin', 'IndexUsed': 'c'},
    {'user': 'hugo', 'IndexUsed': 'a'},
    {'user': 'hugo', 'IndexUsed': 'd'}
]

def combinator(l):
    d = {}
        
    for item in l:
        if(d.get(item['user']) == None):
            d[item['user']] = {item['IndexUsed']}
            pass
        d[item['user']].add(item['IndexUsed'])
        
    return [{'user': key, 'IndexUsed': sorted(value)} for key, value in d.items()]


print(combinator(l))