我不确定我的提问方式是否正确,但这是我的问题:
我有以下格式的字典列表:
[
{'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,但在这里我更愿意将它组合成一个最终的字符串。你能帮我理解如何解决这个问题吗?
答案 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))