Как группировать похожие элементы в списке?

Я собираюсь группировать похожие элементы в списке на основе первых трех символов в строке. Например:

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

Часть .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
>>>

Это не является серьезной проблемой, поскольку оба метода довольно быстрые на небольших строках, но я решил, что я бы сказал об этом.