在 Python 中使用 itertools/more-itertools 对多列列表的项目进行分组和组合

5 python python-itertools

这段代码:

from itertools import groupby, count 
L = [38, 98, 110, 111, 112, 120, 121, 898] 
groups = groupby(L, key=lambda item, c=count():item-next(c))
tmp = [list(g) for k, g in groups]
Run Code Online (Sandbox Code Playgroud)

采用[38, 98, 110, 111, 112, 120, 121, 898],按连续数字对其进行分组,并将它们与最终输出合并:

['38', '98', '110,112', '120,121', '898']
Run Code Online (Sandbox Code Playgroud)

如何对具有多列的列表进行同样的操作,就像下面的列表一样,您可以按名称及其第二列值的连续性对它们进行分组,然后合并。

换句话说,这个数据:

L= [
['Italy','1','3']
['Italy','2','1'],
['Spain','4','2'],
['Spain','5','8'],
['Italy','3','10'],
['Spain','6','4'],
['France','5','3'],
['Spain','20','2']]
Run Code Online (Sandbox Code Playgroud)

应给出以下输出:

[['Italy','1-2-3','3-1-10'],
['France','5','3'],
['Spain','4-5-6','2-8-4'],
['Spain','20','2']]
Run Code Online (Sandbox Code Playgroud)

more-itertools应该更适合这项任务吗?

在 Python 中使用 itertools/more-itertools 对多列列表的项目进行分组和组合

PM *_*ing 0

这本质上是相同的分组技术,但不是使用itertools.countenumerate来生成索引。

首先,我们对数据进行排序,以便将给定国家/地区的所有项目分组在一起,并对数据进行排序。然后我们groupby为每个国家创建一个小组。然后我们groupby在内循环中使用将每个国家/地区的连续数据分组在一起。最后,我们使用zip&.join将数据重新排列成所需的输出格式。

from itertools import groupby
from operator import itemgetter

lst = [
    ['Italy','1','3'],
    ['Italy','2','1'],
    ['Spain','4','2'],
    ['Spain','5','8'],
    ['Italy','3','10'],
    ['Spain','6','4'],
    ['France','5','3'],
    ['Spain','20','2'],
]

newlst = [[country] + ['-'.join(s) for s in zip(*[v[1][1:] for v in g])]
    for country, u in groupby(sorted(lst), itemgetter(0))
        for _, g in groupby(enumerate(u), lambda t: int(t[1][1]) - t[0])]

for row in newlst:
    print(row)
Run Code Online (Sandbox Code Playgroud)

输出

['France', '5', '3']
['Italy', '1-2-3', '3-1-10']
['Spain', '20', '2']
['Spain', '4-5-6', '2-8-4']
Run Code Online (Sandbox Code Playgroud)

我承认这lambda有点神秘;最好使用适当的def函数来代替。几分钟后我会在这里添加。


这是使用更具可读性的按键函数实现的相同操作。

def keyfunc(t):
    # Unpack the index and data
    i, data = t
    # Get the 2nd column from the data, as an integer
    val = int(data[1])
    # The difference between val & i is constant in a consecutive group
    return val - i

newlst = [[country] + ['-'.join(s) for s in zip(*[v[1][1:] for v in g])]
    for country, u in groupby(sorted(lst), itemgetter(0))
        for _, g in groupby(enumerate(u), keyfunc)]
Run Code Online (Sandbox Code Playgroud)