如何解决Itertools groupby 按两个值组织字典列表
我正在尝试按出生状态以及他们是否有零钱来组织价值观。 Itertools groupby 函数看起来是最简单的方法,但我正在努力实现它。也可以打开其他选项。
users = [
{"name": "John","state_of_birth": "CA","money": 0},{"name": "Andrew","money": 300},{"name": "Scott","state_of_birth": "OR","money": 20},{"name": "Travis","state_of_birth": "NY",{"name": "Bill",{"name": "Mike","money": 0}
]
desired_output = [
[{"name": "John","money": 0}],[{"name": "Andrew","money": 300}],[{"name": "Scott","money": 20}],[{"name": "Travis","money": 0}]
]
解决方法
您可以像这样使用 itertools
:
import itertools
def func(x):
return tuple([x['state_of_birth'],x['money'] != 0])
desired_output = list(list(v) for _,v in itertools.groupby(sorted(users,key=func),func))
group_by
函数是一个生成 key
和 value
的生成器。密钥派生自我们传递给 key_function
的 itertools.groupb_by()
。在您的情况下,keys
并不重要,这就是它在 for _,v
中被忽略的原因。
输出:
[{'name': 'John','state_of_birth': 'CA','money': 0},{'name': 'Bill','money': 0}]
[{'name': 'Andrew','money': 300}]
[{'name': 'Travis','state_of_birth': 'NY',{'name': 'Mike','money': 0}]
[{'name': 'Scott','state_of_birth': 'OR','money': 20}]
,
代码:
users = [
{"name": "John","state_of_birth": "CA","money": 0},{"name": "Andrew","money": 300},{"name": "Scott","state_of_birth": "OR","money": 20},{"name": "Travis","state_of_birth": "NY",{"name": "Bill",{"name": "Mike","money": 0}
]
result = {}
for user in users:
key = (user["state_of_birth"],user["money"])
if key in result:
result[key].extend([user])
else:
result[key] = [user]
for _,v in result.items():
print(v)
结果:
[{'name': 'John','money': 300}]
[{'name': 'Scott','money': 20}]
[{'name': 'Travis','money': 0}]
,
如果我理解正确,您的结构是 List[Dict]
并且您想要获得一个 List[List[Dict]]
,其中内部列表包含具有相同 state_of_birth
和 {{ 1}} 布尔值。
我想说最简单的解决方案实际上是使用 money > 0
pandas
根据问题的上下文,您最好保持数据框/表格格式
,您需要确保 groupby
函数的输入已排序。您可以使用与分组相同的按键功能:
users = [
{"name": "John","money": 0}
]
def selector(item): return (item.get('state_of_birth'),item.get('money') != 0)
sorted_users = sorted(users,key=selector)
result = [list(group) for _,group in groupby(sorted_users,selector) ]
输出:
[
[{'name': 'John','money': 0}],[{'name': 'Andrew','money': 300}],[{'name': 'Travis',[{'name': 'Scott','money': 20}]
]
,
虽然它的名字看起来应该是这样,但 itertools.groupby
不是正确的函数,因为它需要对数据进行预先排序。对于一个应该是 O(n) 的算法,排序会使你的时间复杂度变为 O(n log(n))。
从正确的角度来看,如果您有 100 万条记录要排序,而不是 100 万次迭代,如果您使用 groupby
而不是循环和 dict,您现在有 2000 万次迭代。这是一个非常显着的性能损失。
如果 groupby
编写起来更简洁或没有导入,这可能是合理的,但与使用普通循环和字典的更简单方法相比,它的可读性较差。
Pandas 很好,但真的没有理由使用它,除非你已经这样做了。这就像乘坐航天飞机烤西葫芦一样。
您可以使用 defaultdict
和循环:
from collections import defaultdict
from pprint import pprint
users = [
{"name": "John",]
grouped = defaultdict(list)
groupby = "state_of_birth","money"
for user in users:
grouped[tuple([user[k] for k in groupby])].append(user)
pprint([*grouped.values()])
如果您想要“钱非零”而不仅仅是 "money"
值本身,您可以使用自定义分组函数:
grouped = defaultdict(list)
def group_by(x):
return x["state_of_birth"],x["money"] != 0
for user in users:
grouped[group_by(user)].append(user)
result = [*grouped.values()]
或内联逻辑:
grouped = defaultdict(list)
for user in users:
grouped[user["state_of_birth"],user["money"] != 0].append(user)
result = [*grouped.values()]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。