2014-12-26 19 views
11

Szukam grupowania podobnych elementów na liście na podstawie pierwszych trzech znaków w ciągu. Na przykład:Jak grupować podobne elementy na liście?

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

Jak mogę grupa powyższe elementy listy na grupy na podstawie pierwszej z grup liter (np 'abc')? Poniżej znajduje się przeznaczony wyjściowa:

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

lub

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

Próbowałem, używając itertools.groupby do osiągnięcia tego celu bez powodzenia:

>>> 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']] 

Mam spojrzał na następujące posty bez powodzenia:

How to merge similar items in a list. Przykład grupuje podobne elementy (np. 'house' i 'Hose'), stosując podejście, które jest zbyt skomplikowane dla mojego przykładu.

How can I group equivalent items together in a Python list?. Tam właśnie znalazłem pomysł na zrozumienie listy.

Odpowiedz

8

Część .split("_")[0] powinna znajdować się wewnątrz funkcji jednoargumentowej, którą podaje się jako drugi argument do 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']] 
>>> 

Mając go w for ... części nic nie robi, ponieważ wynik jest natychmiast odrzucane.


Również byłoby nieco bardziej wydajny w użyciu str.partition kiedy chcesz tylko jeden podział:

[list(g) for _, g in itertools.groupby(test, lambda x: x.partition('_')[0])] 

Demo:

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

To nie jest głównym problemem, jak obie metody są dość szybkie na małych strunach, ale pomyślałem, że wspomnę o tym.

+0

Dzięki, to działa świetnie. Niedawno odkryłem, że dobrą praktyką jest upewnienie się, że lista wejściowa została posortowana, np. 'test = sorted (['abc_1_2', 'abc_2_2', 'hij_1_1', 'xyz_1_2', 'xyz_2_2'])'. W przeciwnym razie, jeśli lista wejściowa nie zostanie posortowana, 'itertools.groupby' nie będzie działać zgodnie z oczekiwaniami. – Borealis

+1

Tak, najpierw sortowanie listy jest dobrą praktyką podczas używania 'itertools.groupby'. Dzieje się tak, ponieważ 'groupby' przechwytuje tylko przebiegi o podobnych wartościach. Oznacza to, że może on ominąć niektóre, jeśli lista nie jest posortowana. Nie zawracałem sobie głowy wspomnieniem tego w moim poście, ponieważ główny nacisk położono na to, jak używać 'groupby', a twoja lista była już posortowana. – iCodez

Powiązane problemy