【Python】使用itertools.groupby()进行列表的归类和个数统计

本文介绍了如何使用Python的itertools.groupby()函数对列表进行归类和统计连续元素的个数。从问题来源出发,详细讲解了groupby函数的使用,包括直接使用列表、列表套字典以及使用函数作为参数的场景,并给出了具体的示例代码,帮助读者理解其工作原理和应用。

一、问题来源

刷题的时候想要快速统计一个列表当中连续出现的元素的个数,除了自己实现之外,想要更快速的方式就百度了一下,查到了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函数的方式。
返回结果:返回一个迭代器,具体可以看下面的粒子

1、列表的使用

要求:比如有一个列表: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]
2050之间 : [21, 33, 34, 45]
大于50 : [82, 102]
=================
2050之间 : [34, 21]
大于50 : [102]
小于20 : [1]
2050之间 : [33, 45]
小于20 : [19]
大于50 : [82]

三、注意事项

就是groupby前注意要先按需求排在一起,sort起来或者不需要这样的话,也可以求出每次连续的个数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值