【问题标题】:Filtering a list of dictionaries based on multiple values根据多个值过滤字典列表
【发布时间】:2019-12-27 01:48:36
【问题描述】:

我有一个字典列表,我想根据多个条件进行过滤。列表的简化版本如下所示:

orders = [{"name": "v", "price": 123, "location": "Mars"}, 
          {"name": "x", "price": 223, "location": "Mars"}, 
          {"name": "x", "price": 124, "location": "Mars"}, 
          {"name": "y", "price": 456, "location": "Mars"}, 
          {"name": "z", "price": 123, "location": "Mars"}, 
          {"name": "z", "price": 5623, "location": "Mars"}]

我希望最终得到一个列表,其中包含每个具有相同“名称”键的字典价格最低的字典。 例如,上面会变成:

minimums = [{"name": "v", "price": 123, "location": "Mars"},
            {"name": "x", "price": 124, "location": "Mars"},
            {"name": "y", "price": 456, "location": "Mars"},
            {"name": "z", "price": 123, "location": "Mars"}]

我已经通过讨厌的嵌套 if 语句和 for 循环来实现这一点,但是我希望有一种更“Pythonic”的方式来实现。

重复使用相同的列表或创建一个新列表都可以。

感谢您的帮助。

编辑: 感谢您的回答,我尝试使用以下代码对它们中的每一个进行计时

print("Number of dictionaries in orders: " + str(len(orders)))

t0 = time.time()
sorted_orders = sorted(orders, key=lambda i: i["name"])
t1 = time.time()
sorting_time = (t1 - t0)

t0 = time.time()
listcomp_wikiben = [x for x in orders if all(x["price"] <= y["price"] for y  in orders if x["name"] == y["name"])]
t1 = time.time()
print("listcomp_wikiben: " + str(t1 - t0))

t0 = time.time()
itertools_MrGeek = [min(g[1], key=lambda x: x['price']) for g in groupby(sorted_orders, lambda o: o['name'])]
t1 = time.time()
print("itertools_MrGeek: " + str(t1 - t0 + sorting_time))

t0 = time.time()
itertools_Cory = [min(g, key=lambda j: j["price"]) for k,g in groupby(sorted_orders, key=lambda i: i["name"])]
t1 = time.time()
print("itertools_CoryKramer: " + str(t1 - t0 + sorting_time))

t0 = time.time()
pandas_Trenton = pd.DataFrame(orders)
pandas_Trenton.groupby(['name'])['price'].min()
t1 = time.time()
print("pandas_Trenton_M: " + str(t1 - t0))

结果是:

Number of dictionaries in orders: 20867
listcomp_wikiben:     39.78123s
itertools_MrGeek:      0.01562s
itertools_CoryKramer:  0.01565s
pandas_Trenton_M:      0.29685s

【问题讨论】:

标签: python list dictionary data-structures min


【解决方案1】:

如果您首先按"name" 对列表进行排序,则可以使用itertools.groupby 对它们进行分组,然后使用min 和一个lambda 来查找每个组中的最小"price"

>>> from itertools import groupby
>>> sorted_orders = sorted(orders, key=lambda i: i["name"])
>>> [min(g, key=lambda j: j["price"]) for k,g in groupby(sorted_orders , key=lambda i: i["name"])]
[{'name': 'v', 'price': 123, 'location': 'Mars'},
 {'name': 'x', 'price': 124, 'location': 'Mars'},
 {'name': 'y', 'price': 456, 'location': 'Mars'},
 {'name': 'z', 'price': 123, 'location': 'Mars'}]

【讨论】:

  • 我认为“位置”也可能是排序和分组的一个因素。 key=lambda i: (i["name"], i["location"]) 我想。这个答案提到了根据文档至关重要的排序。
【解决方案2】:

你可以使用itertools.groupby:

from itertools import groupby

print(
    [
        min(g[1], key=lambda x: x['price'])
        for g in groupby(sorted(orders, key=lambda o: o['name']), lambda o: o['name'])
    ]
)

输出:

[
    {'name': 'v', 'price': 123, 'location': 'Mars'},
    {'name': 'x', 'price': 124, 'location': 'Mars'},
    {'name': 'y', 'price': 456, 'location': 'Mars'},
    {'name': 'z', 'price': 123, 'location': 'Mars'}
]

【讨论】:

    【解决方案3】:

    没有 itertools 的解决方案

    [x for x in orders if all(x["price"] <= y["price"] for y in orders if x["name"] == y["name"])]
    

    【讨论】:

      【解决方案4】:

      使用pandas:

      orders = [{"name": "v", "price": 123, "location": "Mars"}, 
                {"name": "x", "price": 223, "location": "Mars"}, 
                {"name": "x", "price": 124, "location": "Mars"}, 
                {"name": "y", "price": 456, "location": "Mars"}, 
                {"name": "z", "price": 123, "location": "Pluto"}, 
                {"name": "z", "price": 5623, "location": "Mars"}]
      
      import pandas as pd
      
      df = pd.DataFrame(orders)
      

      df.groupby(['name', 'location'])['price'].min()
      

      【讨论】:

      • 这对于检查更复杂的数据集非常有用,谢谢
      猜你喜欢
      • 2017-04-22
      • 2015-05-17
      • 2020-02-06
      • 2022-01-19
      • 2018-04-30
      • 1970-01-01
      • 1970-01-01
      • 2014-03-11
      • 1970-01-01
      相关资源
      最近更新 更多