代码之家  ›  专栏  ›  技术社区  ›  James Sulak

如何使用python的itertools.groupby()?

  •  400
  • James Sulak  · 技术社区  · 18 年前

    我还没有找到一个可以理解的关于如何实际使用Python的解释 itertools.groupby() 功能。我要做的是:

    • 拿一个清单-在这种情况下,一个被对象化的孩子 lxml 要素
    • 根据某些标准将其分成若干组
    • 然后分别对这些组中的每个组进行迭代。

    我已经复习过 the documentation 和 the examples 但是我很难把它们应用到简单的数字列表之外。

    那么,我如何使用 itertools.groupby()。 ?我还应该使用其他技术吗?同时,也会感谢对良好“先决条件”阅读的提示。

    12 回复  |  直到 7 年前
        1
  •  563
  •   Mateen Ulhaq    7 年前

    重要注意事项: 你必须 排序你的数据 第一。


    我没有得到的部分是在示例构造中

    groups = []
    uniquekeys = []
    for k, g in groupby(data, keyfunc):
       groups.append(list(g))    # Store group iterator as a list
       uniquekeys.append(k)
    

    k 是当前分组键,并且 g 是一个迭代器,您可以使用它对该分组键定义的组进行迭代。也就是说, groupby 迭代器本身返回迭代器。

    下面是一个例子,使用更清晰的变量名:

    from itertools import groupby
    
    things = [("animal", "bear"), ("animal", "duck"), ("plant", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]
    
    for key, group in groupby(things, lambda x: x[0]):
        for thing in group:
            print "A %s is a %s." % (thing[1], key)
        print " "
    

    这将为您提供输出:

    熊是一种动物。
    鸭子是动物。

    仙人掌是一种植物。

    快艇是一种交通工具。
    校车是一种交通工具。

    在这个例子中, things 是一个元组列表,其中每个元组中的第一项是第二项所属的组。

    这个 groupby() 函数接受两个参数:(1)要分组的数据;(2)要分组的函数。

    在这里, lambda x: x[0] 讲述 组() 将每个元组中的第一个项用作分组键。

    在上面 for 语句, 子句 返回三对(键、组迭代器)-每个唯一键一次。可以使用返回的迭代器对该组中的每个项进行迭代。

    下面是一个使用相同数据的稍微不同的示例,使用列表理解:

    for key, group in groupby(things, lambda x: x[0]):
        listOfThings = " and ".join([thing[1] for thing in group])
        print key + "s:  " + listOfThings + "."
    

    这将为您提供输出:

    动物:熊和鸭。
    植物:仙人掌。
    车辆:快艇和校车。

        2
  •  69
  •   Remi Guan cdlane    10 年前

    你能给我们看看你的密码吗?

    关于python文档的示例非常简单:

    groups = []
    uniquekeys = []
    for k, g in groupby(data, keyfunc):
        groups.append(list(g))      # Store group iterator as a list
        uniquekeys.append(k)
    

    因此,在您的例子中,数据是一个节点列表,keyfunc是标准函数的逻辑所在,然后 groupby() 对数据分组。

    你必须小心 数据排序 按你打电话前的标准 groupby 否则就行不通了。 子句 方法实际上只是遍历一个列表,每当键更改时,它就会创建一个新组。

        3
  •  35
  •   nimish    9 年前

    Neato与Groupby的一个诀窍是在一行中运行长度编码:

    [(c,len(list(cgen))) for c,cgen in groupby(some_string)]
    

    将为您提供两个元组的列表,其中第一个元素是char,第二个元素是重复次数。

    编辑:请注意,这是分隔 itertools.groupby 从SQL GROUP BY 语义:itertools不会(通常也不能)提前对迭代器排序,因此具有相同“key”的组不会合并。

        4
  •  28
  •   pylang    8 年前

    itertools.groupby 是用于分组项的工具。

    从 the docs ,我们进一步了解它可能会做什么:

    # [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

    groupby 对象在组是生成器的位置生成键组对。

    特征

    • a.将连续项目分组在一起
    • b.对一个项目的所有出现项进行分组,给出一个已排序的iterable
    • c.指定如何使用键函数对项进行分组

    比较

    # Define a printer for comparing outputs
    >>> def print_groupby(iterable, key=None):
    ...    for k, g in it.groupby(iterable, key):
    ...        print("key: '{}'--> group: {}".format(k, list(g)))
    

    # Feature A: group consecutive occurrences
    >>> print_groupby("BCAACACAADBBB")
    key: 'B'--> group: ['B']
    key: 'C'--> group: ['C']
    key: 'A'--> group: ['A', 'A']
    key: 'C'--> group: ['C']
    key: 'A'--> group: ['A']
    key: 'C'--> group: ['C']
    key: 'A'--> group: ['A', 'A']
    key: 'D'--> group: ['D']
    key: 'B'--> group: ['B', 'B', 'B']
    
    # Feature B: group all occurrences
    >>> print_groupby(sorted("BCAACACAADBBB"))
    key: 'A'--> group: ['A', 'A', 'A', 'A', 'A']
    key: 'B'--> group: ['B', 'B', 'B', 'B']
    key: 'C'--> group: ['C', 'C', 'C']
    key: 'D'--> group: ['D']
    
    # Feature C: group by a key function
    >>> key = lambda x: x.islower()
    >>> print_groupby(sorted("bCAaCacAADBbB"), key)
    key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
    key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']
    

    使用

    注:后面的几个例子来源于Vctor Terrn的Pycon (talk) (Spanish) 《黎明功夫与伊特陶尔》。也见 子句 source code 用C语言编写。


    响应

    # OP: Yes, you can use `groupby`, e.g. 
    [do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)]
    
        5
  •  24
  •   user650654    13 年前

    另一个例子:

    for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5):
        print key, list(igroup)
    

    结果在

    0 [0, 1, 2, 3, 4]
    1 [5, 6, 7, 8, 9]
    2 [10, 11]
    

    注意,igroup是一个迭代器(文档称之为子迭代器)。

    这有助于对发电机进行分块:

    def chunker(items, chunk_size):
        '''Group items in chunks of chunk_size'''
        for _key, group in itertools.groupby(enumerate(items), lambda x: x[0] // chunk_size):
            yield (g[1] for g in group)
    
    with open('file.txt') as fobj:
        for chunk in chunker(fobj):
            process(chunk)
    

    GroupBy的另一个示例-不排序键时。在下面的示例中,XX中的项按YY中的值分组。在这种情况下,首先输出一组零,然后输出一组一,再输出一组零。

    xx = range(10)
    yy = [0, 0, 0, 1, 1, 1, 0, 0, 0, 0]
    for group in itertools.groupby(iter(xx), lambda x: yy[x]):
        print group[0], list(group[1])
    

    生产:

    0 [0, 1, 2]
    1 [3, 4, 5]
    0 [6, 7, 8, 9]
    
        6
  •  19
  •   Nate Anderson    11 年前

    警告:

    语法列表(groupby(…)将无法按预期方式工作。它似乎会破坏内部迭代器对象,因此使用

    for x in list(groupby(range(10))):
        print(list(x[1]))
    

    将产生:

    []
    []
    []
    []
    []
    []
    []
    []
    []
    [9]
    

    而不是list(groupby(…)),在groupby(…)]中尝试[(k,list(g))for k,g,或者如果经常使用该语法,

    def groupbylist(*args, **kwargs):
        return [(k, list(g)) for k, g in groupby(*args, **kwargs)]
    

    并且可以访问groupby功能,同时避免这些麻烦的(对于小数据)迭代器。

        7
  •  9
  •   nutship user1871712    12 年前

    我想再举一个没有排序的GroupBy不起作用的例子。改编自詹姆斯·苏拉克的例子

    from itertools import groupby
    
    things = [("vehicle", "bear"), ("animal", "duck"), ("animal", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]
    
    for key, group in groupby(things, lambda x: x[0]):
        for thing in group:
            print "A %s is a %s." % (thing[1], key)
        print " "
    

    输出是

    A bear is a vehicle.
    
    A duck is a animal.
    A cactus is a animal.
    
    A speed boat is a vehicle.
    A school bus is a vehicle.
    

    有两组有车辆,而一组只有一组

        8
  •  7
  •   Craig S. Anderson Mark Rajcok    10 年前

    @我试过你的例子,但没用。

    from itertools import groupby 
    [(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')]
    

    输出:

    [('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)]
    

    如你所见,有两个O和两个E,但它们是分开的。这时我意识到您需要对传递给groupby函数的列表进行排序。因此,正确的用法是:

    name = list('Pedro Manoel')
    name.sort()
    [(c,len(list(cs))) for c,cs in groupby(name)]
    

    输出:

    [(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)]
    

    只需记住,如果列表未排序,则GroupBy函数 不会工作 !

        9
  •  5
  •   Aaron Hall    11 年前

    如何使用python的itertools.groupby()?

    您可以使用groupby对要迭代的内容进行分组。你给groupby一个iterable和一个可选的 钥匙 函数/可调用项,用于在项从iterable出来时检查它们,它返回一个迭代器,该迭代器给出键可调用结果的两个元组和另一个iterable中的实际项。从帮助:

    groupby(iterable[, keyfunc]) -> create an iterator which returns
    (key, sub-iterator) grouped by each value of key(value).
    

    下面是一个使用协程按计数分组的GroupBy示例,它使用一个键可调用(在本例中, coroutine.send )只需吐出多少次迭代的计数和元素的分组子迭代器:

    import itertools
    
    
    def grouper(iterable, n):
        def coroutine(n):
            yield # queue up coroutine
            for i in itertools.count():
                for j in range(n):
                    yield i
        groups = coroutine(n)
        next(groups) # queue up coroutine
    
        for c, objs in itertools.groupby(iterable, groups.send):
            yield c, list(objs)
        # or instead of materializing a list of objs, just:
        # return itertools.groupby(iterable, groups.send)
    
    list(grouper(range(10), 3))
    

    印刷品

    [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]
    
        10
  •  5
  •   Aashish Gahlawat    8 年前

    排序和分组

    from itertools import groupby
    
    val = [{'name': 'satyajit', 'address': 'btm', 'pin': 560076}, 
           {'name': 'Mukul', 'address': 'Silk board', 'pin': 560078},
           {'name': 'Preetam', 'address': 'btm', 'pin': 560076}]
    
    
    for pin, list_data in groupby(sorted(val, key=lambda k: k['pin']),lambda x: x['pin']):
    ...     print pin
    ...     for rec in list_data:
    ...             print rec
    ... 
    o/p:
    
    560076
    {'name': 'satyajit', 'pin': 560076, 'address': 'btm'}
    {'name': 'Preetam', 'pin': 560076, 'address': 'btm'}
    560078
    {'name': 'Mukul', 'pin': 560078, 'address': 'Silk board'}
    
        11
  •  1
  •   Arko    9 年前

    我遇到的一个有用的例子可能会有所帮助:

    from itertools import groupby
    
    #user input
    
    myinput = input()
    
    #creating empty list to store output
    
    myoutput = []
    
    for k,g in groupby(myinput):
    
        myoutput.append((len(list(g)),int(k)))
    
    print(*myoutput)
    

    样本输入:14445221

    样品输出:(1,1)(3,4)(1,5)(2,2)(1,1)

        12
  •  1
  •   Sky    7 年前

    您可以编写自己的groupby函数:

               def groupby(data):
                    kv = {}
                    for k,v in data:
                        if k not in kv:
                             kv[k]=[v]
                        else:
                            kv[k].append(v)
               return kv
    
         Run on ipython:
           In [10]: data = [('a', 1), ('b',2),('a',2)]
    
            In [11]: groupby(data)
            Out[11]: {'a': [1, 2], 'b': [2]}
    
    推荐文章