如何在列表中对相似的项目进行分组?

17

我希望能够根据字符串中的前三个字符将列表中相似的项目分组。例如:

test = ['abc_1_2', 'abc_2_2', 'hij_1_1', 'xyz_1_2', 'xyz_2_2']

如何根据首字母分组(例如 'abc'),将上述列表项分成不同的组?以下是预期输出:

output = {1: ('abc_1_2', 'abc_2_2'), 2: ('hij_1_1',), 3: ('xyz_1_2', 'xyz_2_2')}
output = [['abc_1_2', 'abc_2_2'], ['hij_1_1'], ['xyz_1_2', 'xyz_2_2']]

我尝试使用itertools.groupby来完成这个任务,但没有成功:

>>> import os, itertools
>>> test = ['abc_1_2', 'abc_2_2', 'hij_1_1', 'xyz_1_2', 'xyz_2_2']
>>> [list(g) for k.split("_")[0], g in itertools.groupby(test)]
[['abc_1_2'], ['abc_2_2'], ['hij_1_1'], ['xyz_1_2'], ['xyz_2_2']]
我已查看以下帖子但没有成功: 如何合并列表中相似的项。此示例使用了一种对于我的例子过于复杂的方法来分组相似项(例如,'house''Hose')。 如何在Python列表中将等价项分组? 这是我找到列表推导式的灵感来源。
1个回答

13

.split("_")[0] 部分应该放在一个单参数函数中,作为第二个参数传递给 itertools.groupby

>>> import os, itertools
>>> test = ['abc_1_2', 'abc_2_2', 'hij_1_1', 'xyz_1_2', 'xyz_2_2']
>>> [list(g) for _, g in itertools.groupby(test, lambda x: x.split('_')[0])]
[['abc_1_2', 'abc_2_2'], ['hij_1_1'], ['xyz_1_2', 'xyz_2_2']]
>>>

for ... 部分中使用它不起作用,因为结果会立即被丢弃。


此外,当您只需要单个拆分时,使用 str.partition 会稍微更有效率:
[list(g) for _, g in itertools.groupby(test, lambda x: x.partition('_')[0])]

演示:

>>> from timeit import timeit
>>> timeit("'hij_1_1'.split('_')")
1.3149855638076913
>>> timeit("'hij_1_1'.partition('_')")
0.7576401470019234
>>>

这不是一个主要的问题,因为在小字符串上两种方法都非常快,但我想提一下。


1
谢谢,这个很好用。我最近发现一个好习惯是确保输入列表已排序,例如 test = sorted(['abc_1_2', 'abc_2_2', 'hij_1_1', 'xyz_1_2', 'xyz_2_2'])。否则,如果输入列表未排序,itertools.groupby 将无法按预期工作。 - Borealis
1
是的,在使用 itertools.groupby 时,首先对列表进行排序是一个好习惯。这是因为 groupby 只捕获相似值的运行。也就是说,如果列表没有排序,它可能会错过一些内容。尽管如此,我在帖子中并没有提到这一点,因为主要重点是如何使用 groupby,而且您的列表已经排序了。 - user2555451

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接