itertools.groupby实现分组排序

最近工作中遇到一个组内排序的问题,之前类似问题都是使用sql来解决,(比如row_number() over(partition by 分组字段 order by 排序字段 desc))。但是使用代码却是第一次,发现功能强大的itertools模块中的groupby方法可以完美解决此类需求。

当前场景:经过一系列处理后,得到如下列表

li = [{'number': 'CN111', 'title': 'title1', 'date': 20080801},
      {'number': 'CN333', 'title': 'title2', 'date': 20220116},
      {'number': 'CN555', 'title': 'title3', 'date': 20010606},
      {'number': 'CN111', 'title': 'title4', 'date': 20090901},
      {'number': 'CN555', 'title': 'title5', 'date': 20030906},
      {'number': 'CN444', 'title': 'title6', 'date': 20190429},
      {'number': 'CN555', 'title': 'title7', 'date': 20201211},
      {'number': 'CN222', 'title': 'title8', 'date': 20141112},
      {'number': 'CN111', 'title': 'title9', 'date': 20000201},
      {'number': 'CN555', 'title': 'title10', 'date': 20211230},
      {'number': 'CN333', 'title': 'title11', 'date': 20070601}
      ]

提炼后的需求:过滤出每个最新的number信息,例如

{'number': 'CN111', 'title': 'title4', 'date': 20090901}
{'number': 'CN333', 'title': 'title2', 'date': 20220116}

思路:

1.首先对li内所有字典根据分组字段,即number进行排序,目的是将number相同的字典元素排到一起,这一步是必要的,否则后续groupby没法得到正确结果

2.使用groupby进行分组

对groupby简单介绍:

groupby就是对可迭代对象的批量操作,作用就是把可迭代对象中相邻的重复元素挑出来放一起,这也是第一步需要先进行排序的原因

Code:

li.sort(key=itemgetter('number'))  # itemgetter可快速实现对字典列表根据某个指定key进行排序的需求
for key, data in groupby(li, key=itemgetter('number')):
      print(key)
      print(data)
      print(list(data))

Output:

CN111
<itertools._grouper object at 0x000002059D1D73A0>
[{'number': 'CN111', 'title': 'title1', 'date': 20080801}, {'number': 'CN111', 'title': 'title4', 'date': 20090901}, {'number': 'CN111', 'title': 'title9', 'date': 20000201}]
CN222
<itertools._grouper object at 0x000002059D1D7640>
[{'number': 'CN222', 'title': 'title8', 'date': 20141112}]
CN333
<itertools._grouper object at 0x000002059D1D73A0>
[{'number': 'CN333', 'title': 'title2', 'date': 20220116}, {'number': 'CN333', 'title': 'title11', 'date': 20070601}]
CN444
<itertools._grouper object at 0x000002059D1D7640>
[{'number': 'CN444', 'title': 'title6', 'date': 20190429}]
CN555
<itertools._grouper object at 0x000002059D1D73A0>
[{'number': 'CN555', 'title': 'title3', 'date': 20010606}, {'number': 'CN555', 'title': 'title5', 'date': 20030906}, {'number': 'CN555', 'title': 'title7', 'date': 20201211}, {'number': 'CN555', 'title': 'title10', 'date': 20211230}]

不难看出,key为分组字段,data是一个itertools._grouper类型的迭代对象,list(data)表示的是将该迭代对象转化为列表,后续操作都是对list(data)进行操作。

最终代码:

from itertools import groupby
from operator import itemgetter
li = [{'number': 'CN111', 'title': 'title1', 'date': 20080801},
      {'number': 'CN333', 'title': 'title2', 'date': 20220116},
      {'number': 'CN555', 'title': 'title3', 'date': 20010606},
      {'number': 'CN111', 'title': 'title4', 'date': 20090901},
      {'number': 'CN555', 'title': 'title5', 'date': 20030906},
      {'number': 'CN444', 'title': 'title6', 'date': 20190429},
      {'number': 'CN555', 'title': 'title7', 'date': 20201211},
      {'number': 'CN222', 'title': 'title8', 'date': 20141112},
      {'number': 'CN111', 'title': 'title9', 'date': 20000201},
      {'number': 'CN555', 'title': 'title10', 'date': 20211230},
      {'number': 'CN333', 'title': 'title11', 'date': 20070601}
      ]
li.sort(key=itemgetter('number'))  # itemgetter可快速实现对字典列表的根据某个指定key进行排序的需求
for key, data in groupby(li, key=itemgetter('number')):
    tmp = list(data)
    tmp.sort(key=itemgetter('date'), reverse=True)
    print(tmp)
    print(tmp[0])
    print('='*500)

Output:

[{'number': 'CN111', 'title': 'title4', 'date': 20090901}, {'number': 'CN111', 'title': 'title1', 'date': 20080801}, {'number': 'CN111', 'title': 'title9', 'date': 20000201}]
{'number': 'CN111', 'title': 'title4', 'date': 20090901}
====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
[{'number': 'CN222', 'title': 'title8', 'date': 20141112}]
{'number': 'CN222', 'title': 'title8', 'date': 20141112}
====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
[{'number': 'CN333', 'title': 'title2', 'date': 20220116}, {'number': 'CN333', 'title': 'title11', 'date': 20070601}]
{'number': 'CN333', 'title': 'title2', 'date': 20220116}
====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
[{'number': 'CN444', 'title': 'title6', 'date': 20190429}]
{'number': 'CN444', 'title': 'title6', 'date': 20190429}
====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
[{'number': 'CN555', 'title': 'title10', 'date': 20211230}, {'number': 'CN555', 'title': 'title7', 'date': 20201211}, {'number': 'CN555', 'title': 'title5', 'date': 20030906}, {'number': 'CN555', 'title': 'title3', 'date': 20010606}]
{'number': 'CN555', 'title': 'title10', 'date': 20211230}

如上便取到了每个number最新的记录 

posted @ 2022-04-29 18:21  少年不太冷2  阅读(457)  评论(0)    收藏  举报