- 一、问题来源
- 二、groupby概述
- 0、文档介绍
- 1、列表的使用
- 2、列表套字典的使用
- 3、参数选用函数返回的方式使用
- 三、注意事项
刷题的时候想要快速统计一个列表当中连续出现的元素的个数,除了自己实现之外,想要更快速的方式就百度了一下,查到了itertools模块的groupby方法,挺有意思的,所以做一个记录
二、groupby概述 0、文档介绍本段下面有总结,不想看的话这里可以跳过
官方文档指路: python中itertools库的官方文档
节选:
itertools.groupby(iterable, key=None)
Make an iterator that returns consecutive keys and groups from the iterable. The key is a function computing a key value for each element. If not specified or is None, key defaults to an identity function and returns the element unchanged. Generally, the iterable needs to already be sorted on the same key function.
The operation of groupby() is similar to the uniq filter in Unix. It generates a break or new group every time the value of the key function changes (which is why it is usually necessary to have sorted the data using the same key function). That behavior differs from SQL’s GROUP BY which aggregates common elements regardless of their input order.
The returned group is itself an iterator that shares the underlying iterable with groupby(). Because the source is shared, when the groupby() object is advanced, the previous group is no longer visible. So, if that data is needed later, it should be stored as a list:
groups = []
uniquekeys = []
data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
groupby() is roughly equivalent to:
class groupby:
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
def __init__(self, iterable, key=None):
if key is None:
key = lambda x: x
self.keyfunc = key
self.it = iter(iterable)
self.tgtkey = self.currkey = self.currvalue = object()
def __iter__(self):
return self
def __next__(self):
self.id = object()
while self.currkey == self.tgtkey:
self.currvalue = next(self.it) # Exit on StopIteration
self.currkey = self.keyfunc(self.currvalue)
self.tgtkey = self.currkey
return (self.currkey, self._grouper(self.tgtkey, self.id))
def _grouper(self, tgtkey, id):
while self.id is id and self.currkey == tgtkey:
yield self.currvalue
try:
self.currvalue = next(self.it)
except StopIteration:
return
self.currkey = self.keyfunc(self.currvalue)
总结:
itertools.groupby(iterable, key=None)
参数:第一个参数可以传入你要处理的列表,第二个参数可以不填也可以指定规则,具体用哪一个key,或者可以使用函数,使用方式如同lambda函数的方式。
返回结果:返回一个迭代器,具体可以看下面的粒子
要求:比如有一个列表:list1 = [1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0] 想要统计每次连续的1或者连续的0的个数如111 00 11 0 1111 0
看一下groupby的魔法:
from itertools import groupby
list1 = [1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0]
res = groupby(list1)
for k, g in res:
print(k, "----------")
for each in g: # g是一个迭代器,把连续的元素集合在一起
print(k, ":", each)
# res
1 ----------
1 : 1
1 : 1
1 : 1
0 ----------
0 : 0
0 : 0
1 ----------
1 : 1
1 : 1
0 ----------
0 : 0
1 ----------
1 : 1
1 : 1
1 : 1
1 : 1
0 ----------
0 : 0
每个g都是个迭代器,会把当前的k的每一项排列在一起
如果想统计连续的1的最大的个数
from itertools import groupby print(max(len(list(g)) for k, g in groupby(xs) if k==1)) # res 4 # 因为最大连续1的个数是4嘛2、列表套字典的使用
要求:列表中有每个人的信息,找到每个班有多少人
from itertools import groupby
dict3 = {"Name": "Jerry", "Age": 17, "Class": 1}
dict4 = {"Name": "Mark", "Age": 27, "Class": 2}
dict5 = {"Name": "Lucy", "Age": 74, "Class": 1}
dict6 = {"Name": "Kath", "Age": 70, "Class": 3}
dict7 = {"Name": "Kate", "Age": 10, "Class": 1}
list1 = [dict1, dict2, dict3, dict4, dict5, dict6, dict7]
list1.sort(key=lambda x:x["Class"]) # 首先要排序,因为groupby是统计连续的聚合,要让我们的列表按需要groupby的那个key按谁许先排列
for each in list1:
print(each)
print("=================")
res_gb = groupby(list1, key=lambda x:x["Class"])
for key, group in res_gb:
count = 0
for each in group:
count += 1
print(key, ":", each)
print(key, "班一共", count, "人")
# res
# 按照班级排好序
{'Name': 'Zara', 'Age': 6, 'Class': 1}
{'Name': 'Jerry', 'Age': 17, 'Class': 1}
{'Name': 'Lucy', 'Age': 74, 'Class': 1}
{'Name': 'Kate', 'Age': 10, 'Class': 1}
{'Name': 'Mark', 'Age': 27, 'Class': 2}
{'Name': 'Tom', 'Age': 37, 'Class': 3}
{'Name': 'Kath', 'Age': 70, 'Class': 3}
=================
# 1类别下的所有集合
1 : {'Name': 'Zara', 'Age': 6, 'Class': 1}
1 : {'Name': 'Jerry', 'Age': 17, 'Class': 1}
1 : {'Name': 'Lucy', 'Age': 74, 'Class': 1}
1 : {'Name': 'Kate', 'Age': 10, 'Class': 1}
1 班一共 4 人
# 2类别下的所有集合
2 : {'Name': 'Mark', 'Age': 27, 'Class': 2}
2 班一共 1 人
# 3类别下的所有集合
3 : {'Name': 'Tom', 'Age': 37, 'Class': 3}
3 : {'Name': 'Kath', 'Age': 70, 'Class': 3}
3 班一共 2 人
3、参数选用函数返回的方式使用
要求:一个列表,找出大于多少,小于多少的数的集合
from itertools import groupby
list1 = [34, 21, 102, 1, 33, 45, 19, 82]
def my_rule(num):
if num > 50:
return "大于50"
elif num < 20:
return "小于20"
else:
return "20到50之间"
for k, g in groupby(sorted(list1), key=my_rule): # 仍然要先排序,否则不能把分散的聚合在一起
print(k, ":", list(g))
print("=================")
for k, g in groupby(list1, key=my_rule): # 如果不排序,结果如下
print(k, ":", list(g))
# res
小于20 : [1, 19]
20到50之间 : [21, 33, 34, 45]
大于50 : [82, 102]
=================
20到50之间 : [34, 21]
大于50 : [102]
小于20 : [1]
20到50之间 : [33, 45]
小于20 : [19]
大于50 : [82]
三、注意事项
就是groupby前注意要先按需求排在一起,sort起来或者不需要这样的话,也可以求出每次连续的个数



