【问题标题】:Compare and delete lists from a list of lists using max condition使用最大条件从列表列表中比较和删除列表
【发布时间】:2018-10-13 15:55:41
【问题描述】:

我有一个这样的列表:

a=[['2012-05-11','yes','44','426.24'],['2013-03-22','no','12','426.24'],['2018-08-13','yes','88','426.24'] ,['2017-05-11','yes','404','450.24']]

我想删除所有具有相同第 4 个值 ( a[0][3],a[1][3] ...) 的列表,并且只保留具有最近日期的列表, 所以就我而言,我想要这个结果:

a=[['2018-08-13','yes','88','426.24'] ,['2017-05-11','yes','404','450.24']]

有什么想法可以做到这一点吗?

【问题讨论】:

标签: python python-3.x python-2.7 list sorting


【解决方案1】:

从内存使用和运行时的角度来看,作为一种优化方式,您可以循环遍历您的子列表并跟踪那些日期更长的列表。由于您想对最后一项重复的列表执行此操作,因此以最后一项为键的字典是您可以使用的最佳数据结构。

In [2]: from datetime import datetime

In [3]: def filter_func(arr):
   ...:     _container = {}
   ...:     for dt, *mid, last in arr:
   ...:         date_obj = datetime.strptime(dt, '%Y-%m-%d')
   ...:         try:
   ...:             d = _container[last][0]
   ...:             if date_obj > d:
   ...:                  _container[last] = (date_obj, [dt] + mid)
   ...:         except KeyError:
   ...:             _container[last] = (date_obj, [dt] + mid)
   ...:     return [[*rest, last] for last, (_, rest) in _container.items()]

演示:

In [5]: filter_func(a)
Out[5]: [['2018-08-13', 'yes', '88', '426.24'], ['2017-05-11', 'yes', '404', '450.24']]

【讨论】:

    【解决方案2】:

    我最终得到了与@Kasramvd 相同的想法,但代码更易于理解(应该让经验不足的 Python 程序员更清楚地了解这个想法):

    from datetime import datetime
    
    def myfilter (arr):
        results = dict()
    
        for item in arr:
            index = item[3]
            if index not in results or datetime.strptime(item[0], '%Y-%m-%d') > datetime.strptime(results[index][0], '%Y-%m-%d'):
                results[index] = item
    
        print([item for _, item in results.items()])
    

    【讨论】:

      【解决方案3】:

      我将提供一个不使用任何库的解决方案。

      首先,您需要按最后一个字段对项目进行分组。

      dict = {}
      for elem in a:
         if elem[-1] not in dict:
            dict[elem[-1]] = []
         dict[elem[-1]].append(elem[:-1])
      
      print(dict)
      
      {'426.24': [['2012-05-11', 'yes', '44'], ['2013-03-22', 'no', '12'], ['2018-08-13', 'yes', '88']], '450.24': [['2017-05-11', 'yes', '404']]}
      

      然后只保留字典中每个键的最后一项。

      for key in dict:
          dict[key] = sorted([elem[0] for elem in dict[key]], key=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d'))
          dict[key] = dict[key].pop()
      

      然后只需使用list comprehension 来过滤初始数组。

      a = [elem for elem in a if elem[0] == dict[elem[-1]]]
      

      输出

      [['2018-08-13', 'yes', '88', '426.24'], ['2017-05-11', 'yes', '404', '450.24']]
      

      【讨论】:

      • 为什么不使用collections.defaultdict() 对项目进行分组?
      【解决方案4】:

      这是使用collections.defaultdict 的解决方案。这个想法是通过一个键来重构你的字典。然后使用 max 和自定义 key 参数来提取所需的结果。

      from collections import defaultdict
      
      d = defaultdict(list)
      
      for *data, key in a:
          d[key].append(data)
      
      res = [max(v, key=lambda x: datetime.strptime(x[0], '%Y-%m-%d'))+[k]
             for k, v in d.items()]
      
      [['2018-08-13', 'yes', '88', '426.24'],
       ['2017-05-11', 'yes', '404', '450.24']]
      

      【讨论】:

      • 好多了,但仍有改进的余地;))用两个单独的循环来做。一个用于创建字典,另一个用于从字典创建预期的数组(这可能不是必需的)。
      【解决方案5】:

      这可以通过itertools.groupbysorted 的组合来实现。

      以下解决方案明确使用datetime 转换对日期进行排序。

      排序后,只需要提取每个groupby元素的最后一个元素为需要的条目即可。

      from datetime import datetime
      from itertools import groupby
      from operator import itemgetter
      
      sorter = sorted(a, key=lambda x: (x[3], datetime.strptime(x[0], '%Y-%m-%d')))
      grouper = groupby(sorter, key=itemgetter(3))
      
      res = [list(j)[-1] for _, j in grouper]
      
      [['2018-08-13', 'yes', '88', '426.24'],
       ['2017-05-11', 'yes', '404', '450.24']]
      

      【讨论】:

      • @Kasramvd,谢谢 - 我还提供了另一个答案(我不需要代表,但看看社区喜欢什么很有趣)。
      猜你喜欢
      • 2017-01-15
      • 2019-07-14
      • 1970-01-01
      • 2015-10-31
      • 1970-01-01
      • 1970-01-01
      • 2011-05-17
      • 2019-03-22
      • 2022-12-23
      相关资源
      最近更新 更多