Python Itertools groupby按两个值组织字典列表

Python Itertools groupby按两个值组织字典列表,python,itertools,Python,Itertools,我试图按照出生状态以及他们是否有钱来组织价值观。Itertools groupby函数看起来是最简单的方法,但我正在努力实现它。对其他选择也持开放态度 如果我有一个这样的字典列表 users = [ {"name": "John", "state_of_birth": "CA", "money": 0}, {"name": &qu

我试图按照出生状态以及他们是否有钱来组织价值观。Itertools groupby函数看起来是最简单的方法,但我正在努力实现它。对其他选择也持开放态度

如果我有一个这样的字典列表

users = [
            {"name": "John", "state_of_birth": "CA", "money": 0},
            {"name": "Andrew", "state_of_birth": "CA", "money": 300},
            {"name": "Scott", "state_of_birth": "OR", "money": 20},
            {"name": "Travis", "state_of_birth": "NY", "money": 0},
            {"name": "Bill", "state_of_birth": "CA", "money": 0},
            {"name": "Mike", "state_of_birth": "NY", "money": 0}
        ]
我正在尝试获取此输出

desired_output = [
            [{"name": "John", "state_of_birth": "CA", "money": 0}, {"name": "Bill", "state_of_birth": "CA", "money": 0}],
            [{"name": "Andrew", "state_of_birth": "CA", "money": 300}],
            [{"name": "Scott", "state_of_birth": "OR", "money": 20}],
            [{"name": "Travis", "state_of_birth": "NY", "money": 0},{"name": "Mike", "state_of_birth": "NY", "money": 0}]
            ]

您可以像这样使用
itertools

导入itertools
def func(x):
返回元组([x['state\u of_birth'],x['money']!=0])
所需的_输出=列表(itertools.groupby(排序(用户,key=func,func))中的v的列表(v))
group\u by
函数是一个生成
的生成器。键是从传递给
itertools.groupb\u by()
key\u函数派生的。在您的情况下,将
键设置为不重要,这就是为什么在
for v,v
中忽略该键的原因

输出:

[
    [{'name': 'John', 'state_of_birth': 'CA', 'money': 0}, {'name': 'Bill', 'state_of_birth': 'CA', 'money': 0}],
    [{'name': 'Andrew', 'state_of_birth': 'CA', 'money': 300}], 
    [{'name': 'Travis', 'state_of_birth': 'NY', 'money': 0}, {'name': 'Mike', 'state_of_birth': 'NY', 'money': 0}],
    [{'name': 'Scott', 'state_of_birth': 'OR', 'money': 20}]
]
[{'name':'John','state\u of u chirth':'CA','money':0},{'name':'Bill','state\u of u chirth':'CA','money':0}]
[{'name':'Andrew','state_of_borning':'CA','money':300}]
[{'name':'Travis','NY','money':0},{'name':'Mike','state'u'u'u'u'u borning':'NY','money':0}]
[{'name':'Scott','state_of_born':'或''money':20}]
代码:

users = [
            {"name": "John", "state_of_birth": "CA", "money": 0},
            {"name": "Andrew", "state_of_birth": "CA", "money": 300},
            {"name": "Scott", "state_of_birth": "OR", "money": 20},
            {"name": "Travis", "state_of_birth": "NY", "money": 0},
            {"name": "Bill", "state_of_birth": "CA", "money": 0},
            {"name": "Mike", "state_of_birth": "NY", "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', 'state_of_birth': 'CA', 'money': 0}, {'name': 'Bill', 'state_of_birth': 'CA', 'money': 0}]
[{'name': 'Andrew', 'state_of_birth': 'CA', 'money': 300}]
[{'name': 'Scott', 'state_of_birth': 'OR', 'money': 20}]
[{'name': 'Travis', 'state_of_birth': 'NY', 'money': 0}, {'name': 'Mike', 'state_of_birth': 'NY', 'money': 0}]

如果我理解正确的话,你有一个结构是
List[Dict]
,你想得到一个
List[List[Dict]
,其中内部列表包含具有相同
出生状态
货币>0
布尔值的词典

我想说最简单的解决方法实际上是使用
pandas

将熊猫作为pd导入
用户=[
{“姓名”:“约翰”,“出生州”:“CA”,“货币”:0},
{“姓名”:“安德鲁”,“出生州”:“CA”,“货币”:300},
{“姓名”:“斯科特”,“出生州”:“或”,“金钱”:20},
{“姓名”:“特拉维斯”,“出生州”:“纽约”,“货币”:0},
{“姓名”:“比尔”,“出生州”:“CA”,“货币”:0},
{“姓名”:“迈克”,“出生州”:“纽约”,“货币”:0}
]
df=pd.DataFrame.from_记录(用户)
#我们需要一个列来指示money>0
df[“货币”]=df[“货币”]>0
#groupby为您提供了Tuple[key,sub-dataframe]的迭代器
#dfs现在保存分组数据帧的列表
dfs=[tup[1]表示df.groupby中的tup([“出生状态”、“金钱”])]
#如果你想的话,现在可以删除money\u bool列
dfs=[df.drop(“money\u bool”,axis=1)表示dfs中的df]
所需的输出=[df.到dfs中df的dict(“记录”)]

根据问题的上下文,最好使用数据帧/表格格式

您需要确保对
groupby
函数的输入进行排序。您可以使用与分组相同的键功能:

users = [
            {"name": "John", "state_of_birth": "CA", "money": 0},
            {"name": "Andrew", "state_of_birth": "CA", "money": 300},
            {"name": "Scott", "state_of_birth": "OR", "money": 20},
            {"name": "Travis", "state_of_birth": "NY", "money": 0},
            {"name": "Bill", "state_of_birth": "CA", "money": 0},
            {"name": "Mike", "state_of_birth": "NY", "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', 'state_of_birth': 'CA', 'money': 0}, {'name': 'Bill', 'state_of_birth': 'CA', 'money': 0}],
    [{'name': 'Andrew', 'state_of_birth': 'CA', 'money': 300}], 
    [{'name': 'Travis', 'state_of_birth': 'NY', 'money': 0}, {'name': 'Mike', 'state_of_birth': 'NY', 'money': 0}],
    [{'name': 'Scott', 'state_of_birth': 'OR', 'money': 20}]
]

虽然它的名字似乎应该是一种方式,但使用
itertools.groupby
不是正确的函数,因为它需要对数据进行预排序。对于一个应该是O(n)的算法,排序会使时间复杂度达到O(n log(n))

从这个角度来看,如果你有一百万条记录要排序,而不是一百万次迭代,那么如果你使用
groupby
而不是循环和dict,你现在有2000万次迭代。这是一个相当大的性能损失

如果
groupby
编写起来更简洁,或者没有导入,这可能是合理的,但它的可读性不如使用普通循环和字典的简单方法

熊猫很好,但是没有理由使用它,除非你已经这么做了。这就像带着航天飞机来烤西葫芦一样

您可以使用
defaultdict
和循环:

from collections import defaultdict
from pprint import pprint

users = [
    {"name": "John", "state_of_birth": "CA", "money": 0},
    {"name": "Andrew", "state_of_birth": "CA", "money": 300},
    {"name": "Scott", "state_of_birth": "OR", "money": 20},
    {"name": "Travis", "state_of_birth": "NY", "money": 0},
    {"name": "Bill", "state_of_birth": "CA", "money": 0},
    {"name": "Mike", "state_of_birth": "NY", "money": 0},
]

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 is non zero”而不仅仅是
“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()]

我在这里没有看到任何代码尝试。你能分享一下吗?谢谢顺便说一句,groupby可能不会在这里工作。我会在defaultdict中创建元组键。我使用了多次循环遍历所有内容的代码,但我认为这会让未来的观众的问题更加复杂。我不知道如何使用itertools。不,最好展示一下你的尝试。未来的用户可能会看到你的代码,然后想,哇,我做了同样的事情,遇到了同样的问题——我怎样才能修复它?然后他们滚动到答案。没有这一点,背景对每个人来说都是一个谜。添加代码也有助于澄清意图和您的规范,尽管这里看起来很清楚。通常情况下,让某人进行一次非工作性尝试比从头开始给出答案更具指导意义,做出可能不准确的假设。查看预期输出,您也没有使用
金钱
键also@deadshot你说得对。现在金钱被认为是外部元组()调用,函数中的[]不必存在,对吗?
return(x[‘出生国’],x[‘金钱’!=0)