【问题标题】:How to filter list of dictionaries in python?如何过滤python中的字典列表?
【发布时间】:2022-01-23 11:56:53
【问题描述】:

我有一个字典列表,如下-

VehicleList = [
        {
            'id': '1',
            'VehicleType': 'Car',
            'CreationDate': datetime.datetime(2021, 12, 10, 16, 9, 44, 872000)
        },
        {
            'id': '2',
            'VehicleType': 'Bike',
            'CreationDate': datetime.datetime(2021, 12, 15, 11, 8, 21, 612000)
        },
        {
            'id': '3',
            'VehicleType': 'Truck',
            'CreationDate': datetime.datetime(2021, 9, 13, 10, 1, 50, 350095)
        },
        {
            'id': '4',
            'VehicleType': 'Bike',
            'CreationDate': datetime.datetime(2021, 12, 10, 21, 1, 00, 300012)
        },
        {
            'id': '5',
            'VehicleType': 'Car',
            'CreationDate': datetime.datetime(2021, 12, 21, 10, 1, 50, 600095)
        }
    ]

如何根据“CreationDate”获取每个“VehicleType”的最新车辆列表?

我期待这样的事情-

latestVehicles = [
        {
            'id': '5',
            'VehicleType': 'Car',
            'CreationDate': datetime.datetime(2021, 12, 21, 10, 1, 50, 600095)
        },
        {
            'id': '2',
            'VehicleType': 'Bike',
            'CreationDate': datetime.datetime(2021, 12, 15, 11, 8, 21, 612000)
        },
        {
            'id': '3',
            'VehicleType': 'Truck',
            'CreationDate': datetime.datetime(2021, 9, 13, 10, 1, 50, 350095)
        }
    ]

我尝试根据每个字典的“VehicleType”将它们分离到不同的列表中,然后根据它们的“CreationDate”对它们进行排序,然后选择最新的。

我相信可能有更好的方法来做到这一点。

【问题讨论】:

    标签: python list sorting dictionary datetime


    【解决方案1】:

    Blckknght's answer 的一种变体,使用 defaultdict 来避免长 if 条件:

    from collections import defaultdict
    import datetime
    from operator import itemgetter
    
    latest_dict = defaultdict(lambda: {'CreationDate': datetime.datetime.min})
    
    for vehicle in VehicleList:
        t = vehicle['VehicleType']
        latest_dict[t] = max(vehicle, latest_dict[t], key=itemgetter('CreationDate'))
    
    latestVehicles = list(latest_dict.values())
    

    最新车辆:

    [{'id': '5', 'VehicleType': 'Car', 'CreationDate': datetime.datetime(2021, 12, 21, 10, 1, 50, 600095)},
     {'id': '2', 'VehicleType': 'Bike', 'CreationDate': datetime.datetime(2021, 12, 15, 11, 8, 21, 612000)},
     {'id': '3', 'VehicleType': 'Truck', 'CreationDate': datetime.datetime(2021, 9, 13, 10, 1, 50, 350095)}]
    

    【讨论】:

      【解决方案2】:

      一个更易读的代码的小请求:

      from operator import itemgetter
      from itertools import groupby
      
      vtkey = itemgetter('VehicleType')
      cdkey = itemgetter('CreationDate')
      
      latest = [
          # Get latest from each group.
          max(vs, key = cdkey)
          # Sort and group by VehicleType.
          for g, vs in groupby(sorted(vehicles, key = vtkey), vtkey)
      ]
      

      【讨论】:

        【解决方案3】:

        这是使用maxfilter 的解决方案:

        VehicleLatest = [
            max(
                filter(lambda _: _["VehicleType"] == t, VehicleList), 
                key=lambda _: _["CreationDate"]
            ) for t in {_["VehicleType"] for _ in VehicleList}
        ]
        

        结果

        print(VehicleLatest)
        # [{'id': '2', 'VehicleType': 'Bike', 'CreationDate': datetime.datetime(2021, 12, 15, 11, 8, 21, 612000)}, {'id': '3', 'VehicleType': 'Truck', 'CreationDate': datetime.datetime(2021, 9, 13, 10, 1, 50, 350095)}, {'id': '5', 'VehicleType': 'Car', 'CreationDate': datetime.datetime(2021, 12, 21, 10, 1, 50, 600095)}]
        

        【讨论】:

        • VehicleLatest 必须包含“id”为 2、3 和 5 的车辆,但您的解决方案提供了“id”为 1、2 和 3 的车辆。
        • @NeutrinoWatson 我有一个错字(在 lambda 函数中忘记了 _)。修复它
        【解决方案4】:

        您可以使用运算符来实现该目标:

        import operator
        my_sorted_list_by_type_and_date = sorted(VehicleList, key=operator.itemgetter('VehicleType', 'CreationDate'))
        

        【讨论】:

          【解决方案5】:

          这在pandas 中非常简单明了。首先将 dicts 列表加载为 pandas 数据框,然后按日期对值进行排序,取出前 n 个项目(下例中为 3 个),然后导出到 dict。

          import pandas as pd
          
          df = pd.DataFrame(VehicleList)
          df.sort_values('CreationDate', ascending=False).head(3).to_dict(orient='records')
          

          【讨论】:

            【解决方案6】:

            'VehicleType''CreationDate' 排序,然后根据'VehicleType' 和车辆创建字典,以获取每种类型的最新车辆:

            VehicleList.sort(key=lambda x: (x.get('VehicleType'), x.get('CreationDate')))
            out = list(dict(zip([item.get('VehicleType') for item in VehicleList], VehicleList)).values())
            

            输出:

            [{'id': '2',
              'VehicleType': 'Bike',
              'CreationDate': datetime.datetime(2021, 12, 15, 11, 8, 21, 612000)},
             {'id': '5',
              'VehicleType': 'Car',
              'CreationDate': datetime.datetime(2021, 12, 21, 10, 1, 50, 600095)},
             {'id': '3',
              'VehicleType': 'Truck',
              'CreationDate': datetime.datetime(2021, 9, 13, 10, 1, 50, 350095)}]
            

            【讨论】:

              【解决方案7】:

              使用从VehicleType 值到最终列表中所需的字典的字典映射。将输入列表中每个项目的日期与您的字典中的日期进行比较,并保留后一个。

              latest_dict = {}
              
              for vehicle in VehicleList:
                  t = vehicle['VehicleType']
                  if t not in latest_dict or vehicle['CreationDate'] > latest_dict[t]['CreationDate']:
                      latest_dict[t] = vehicle
              
              latestVehicles = list(latest_dict.values())
              

              【讨论】:

              • 不像其他一些那样花哨,但时间短、易于理解和线性(如果 latest_dict 查找被认为是 O(1))。
              【解决方案8】:

              我认为你可以使用 itertools 中的 groupby 函数来实现你想要的。

              from itertools import groupby
              
              # entries sorted according to the key we wish to groupby: 'VehicleType'
              VehicleList = sorted(VehicleList, key=lambda x: x["VehicleType"])
              
              latestVehicles = []
              
              # Then the elements are grouped.
              for k, v in groupby(VehicleList, lambda x: x["VehicleType"]):
                  # We then append to latestVehicles the 0th entry of the
                  # grouped elements after sorting according to the 'CreationDate'
                  latestVehicles.append(sorted(list(v), key=lambda x: x["CreationDate"], reverse=True)[0])
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2023-03-23
                • 2017-10-29
                • 2018-04-30
                • 2022-01-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多