2014-12-26 4 views
11

Sto cercando di raggruppare elementi simili in un elenco basato sui primi tre caratteri nella stringa. Per esempio:Come raggruppare oggetti simili in un elenco?

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

Come posso raggruppare gli elementi della lista di cui sopra in gruppi sulla base del primo gruppo di lettere (ad esempio 'abc')? Quanto segue è la produzione diretta:

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

o

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

Ho provato con itertools.groupby per raggiungere questo senza successo:

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

Ho esaminato i seguenti messaggi senza successo:

How to merge similar items in a list. L'esempio raggruppa elementi simili (ad esempio 'house' e 'Hose') utilizzando un approccio che è troppo complicato per il mio esempio.

How can I group equivalent items together in a Python list?. È qui che ho trovato l'idea per la comprensione delle liste.

risposta

8

La parte .split("_")[0] deve essere all'interno di una funzione a argomento singolo passata come secondo argomento a 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']] 
>>> 

Averlo nella parte for ... non fa nulla in quanto il risultato è immediatamente scartato.


Inoltre, sarebbe un po 'più efficiente di utilizzare str.partition quando si desidera una sola spaccatura:

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

Questa non è una preoccupazione importante come entrambi i metodi sono piuttosto veloci su stringhe piccole, ma ho pensato di parlarne.

+0

Grazie, funziona benissimo. Recentemente ho scoperto che è una buona pratica assicurarsi che l'elenco di input sia ordinato per es. 'test = ordinato (['abc_1_2', 'abc_2_2', 'hij_1_1', 'xyz_1_2', 'xyz_2_2'])'. Altrimenti, se l'elenco di input non è ordinato, 'itertools.groupby' non funzionerà come previsto. – Borealis

+1

Sì, l'ordinamento dell'elenco è una buona pratica quando si utilizza 'itertools.groupby'. Questo perché 'groupby' acquisisce solo esecuzioni di valori simili. Significa che può mancare qualcosa se la lista non è ordinata. Non mi sono preoccupato di menzionarlo nel mio post, anche perché l'obiettivo principale era su come usare 'groupby' e anche il tuo elenco era già stato ordinato. – iCodez