2011-06-15 9 views
23

Tengo una lista de enteros y quiero poder identificar bloques contiguos de duplicados: es decir, quiero producir una lista de duples que preserve la orden donde cada duples contenga (int_in_question, number of occurrences).¿Cuál es la forma más pitonica de identificar duplicados consecutivos en una lista?

Por ejemplo, si tengo una lista como:

[0, 0, 0, 3, 3, 2, 5, 2, 6, 6] 

quiero que el resultado sea:

[(0, 3), (3, 2), (2, 1), (5, 1), (2, 1), (6, 2)] 

tengo bastante forma sencilla de hacer esto con un para- loop, temp y contador:

result_list = [] 
current = source_list[0] 
count = 0 
for value in source_list: 
    if value == current: 
     count += 1 
    else: 
     result_list.append((current, count)) 
     current = value 
     count = 1 
result_list.append((current, count)) 

Pero me gusta mucho el func de python modismos de programación, y me gustaría poder hacer esto con una expresión de generador simple. Sin embargo, me resulta difícil mantener subcuentas cuando se trabaja con generadores. Tengo la sensación de que un proceso de dos pasos podría llevarme allí, pero por ahora estoy perplejo.

¿Existe una forma particularmente elegante/pitónica de hacerlo, especialmente con generadores?

+5

Como referencia, este proceso se llama: http://en.wikipedia.org/wiki/Run-length_encoding –

Respuesta

43
>>> from itertools import groupby 
>>> L = [0, 0, 0, 3, 3, 2, 5, 2, 6, 6] 
>>> grouped_L = [(k, sum(1 for i in g)) for k,g in groupby(L)] 
>>> # Or (k, len(list(g))), but that creates an intermediate list 
>>> grouped_L 
[(0, 3), (3, 2), (2, 1), (5, 1), (2, 1), (6, 2)] 

Batteries included, como se suele decir.

Sugerencia para usar sum y la expresión del generador de JBernardo; Ver comentario.

+0

Excelente, esto es exactamente lo que estaba buscando. Apreciar la ayuda, muchas gracias. –

+0

@machine: ¡De nada! –

+9

+1, tal vez podría cambiar 'len (list (g))' por 'sum (1 for i in g)' para evitar el almacenamiento intermedio. – JBernardo

Cuestiones relacionadas