2012-05-02 24 views
11

que tiene una lista de números enteros ...lista de grupos de enteros por secuencia continua

[1,2,3,4,5,8,9,10,11,200,201,202] 

me gustaría agruparlos en una lista de listas que cada sub-lista contiene números enteros cuya secuencia no se ha roto. Así ...

[[1,5],[8,11],[200,202]] 

que tienen una obra más bien precarios sobre ...

lSequenceOfNum = [1,2,3,4,5,8,9,10,11,200,201,202] 

lGrouped = [] 
start = 0 
for x in range(0,len(lSequenceOfNum)): 
    if x != len(lSequenceOfNum)-1: 
     if(lSequenceOfNum[x+1] - lSequenceOfNum[x]) > 1: 
      lGrouped.append([lSequenceOfNum[start],lSequenceOfNum[x]]) 
      start = x+1 

    else: 
     lGrouped.append([lSequenceOfNum[start],lSequenceOfNum[x]]) 
print lGrouped 

Es lo mejor que podía hacer. ¿Hay una forma más "pitonica" de hacer esto? Gracias ..

+0

Piense en ello en términos de dónde son los saltos en lugar de en el que el los rangos son Puede almacenar los resultados en una matriz simple de entradas donde cada entrada es un índice correspondiente a un salto en la matriz original. Creo que esto es más simple ... y en caso de que esto sea reutilizable o código de biblioteca, puede encapsular todo eso en el funcionamiento de una clase. – djechlin

+0

Estoy bastante seguro de que este es un duplicado, aunque no puedo buscarlo ahora mismo. – jamylak

Respuesta

12

Suponiendo que la lista estará siempre en orden ascendente:

from itertools import groupby, count 

numberlist = [1,2,3,4,5,8,9,10,11,200,201,202] 

def as_range(g): 
    l = list(g) 
    return l[0], l[-1] 

print [as_range(g) for _, g in groupby(numberlist, key=lambda n, c=count(): n-next(c))] 
+0

¡Perfecto! Gracias. – b10hazard

0

pseudo código (con off-by-one errores a corregir):

jumps = new array; 
for idx from 0 to len(array) 
if array[idx] != array[idx+1] then jumps.push(idx); 

Creo que esto es en realidad un caso en el que tiene sentido trabajar con los índices (como en C, antes java/python/perl/etc. mejorado sobre esto) en lugar de los objetos en la matriz.

0

Aquí hay una versión que debe ser fácil de leer:

def close_range(el, it): 
    while True: 
     el1 = next(it, None) 
     if el1 != el + 1: 
      return el, el1 
     el = el1 

def compress_ranges(seq): 
    iterator = iter(seq) 
    left = next(iterator, None) 
    while left is not None: 
     right, left1 = close_range(left, iterator) 
     yield (left, right) 
     left = left1 

list(compress_ranges([1, 2, 3, 4, 5, 8, 9, 10, 11, 200, 201, 202])) 
4

me di cuenta que tenía demasiado complicado esto un poco, mucho más fácil acaba de contar manualmente de utilizar un generador poco enrevesada:

def ranges(seq): 
    start, end = seq[0], seq[0] 
    count = start 
    for item in seq: 
     if not count == item: 
      yield start, end 
      start, end = item, item 
      count = item 
     end = item 
     count += 1 
    yield start, end 

print(list(ranges([1,2,3,4,5,8,9,10,11,200,201,202]))) 

Producir:

[(1, 5), (8, 11), (200, 202)] 

Este método es bastante rápido:

Este método (y el viejo, que realizan casi exactamente el mismo):

python -m timeit -s "from test import ranges" "ranges([1,2,3,4,5,8,9,10,11,200,201,202])" 
1000000 loops, best of 3: 0.47 usec per loop 

Jeff Mercado's Method:

python -m timeit -s "from test import as_range; from itertools import groupby, count" "[as_range(g) for _, g in groupby([1,2,3,4,5,8,9,10,11,200,201,202], key=lambda n, c=count(): n-next(c))]" 
100000 loops, best of 3: 11.1 usec per loop 

Eso es más de 20 veces más rápido, aunque, naturalmente, a menos que la velocidad sea importante, esto no es una preocupación real.


mi solución de edad utilizando generadores:

import itertools 

def resetable_counter(start): 
    while True: 
     for i in itertools.count(start): 
      reset = yield i 
      if reset: 
       start = reset 
       break 

def ranges(seq): 
    start, end = seq[0], seq[0] 
    counter = resetable_counter(start) 
    for count, item in zip(counter, seq): #In 2.x: itertools.izip(counter, seq) 
     if not count == item: 
      yield start, end 
      start, end = item, item 
      counter.send(item) 
     end = item 
    yield start, end 

print(list(ranges([1,2,3,4,5,8,9,10,11,200,201,202]))) 

Producción:

[(1, 5), (8, 11), (200, 202)] 
+0

¿Estás seguro de que esto funciona? – Abhijit

+0

@Abhijit Bastante seguro, lo probé. ¿Has encontrado que falla? –

+0

Bueno, no estoy seguro, pero el o/p no es lo que debería esperarse. ¿Puedes echar un vistazo a este [IDEONE RUN] (http://ideone.com/3sCnZ) – Abhijit

2

Usted puede hacer esto de manera eficiente en tres pasos

dados

list1=[1,2,3,4,5,8,9,10,11,200,201,202] 

Calcular la discontinuidad

 [1,2,3,4,5,8,9,10,11 ,200,201,202] 
-  [1,2,3,4,5,8,9 ,10 ,11 ,200,201,202] 
---------------------------------------- 
     [1,1,1,1,3,1,1 ,1 ,189,1 ,1] 
(index) 1 2 3 4 5 6 7 8 9 10 11 
       *   * 
rng = [i+1 for i,e in enumerate((x-y for x,y in zip(list1[1:],list1))) if e!=1] 
>>> rng 
[5, 9] 

Añadir los límites

rng = [0] + rng + [len(list1)] 
>>> rng 
[0, 5, 9,12] 

ahora calcular la continuidad real oscila

[(list1[i],list1[j-1]) for i,j in zip(list2,list2[1:])] 
[(1, 5), (8, 11), (200, 202)] 

LB    [0, 5, 9, 12] 
UB    [0, 5, 9, 12] 
    ----------------------- 
indexes (LB,UB-1) (0,4) (5,8) (9,11) 
+0

+1, buena explicación :) –

0

preguntas similares:
Python - find incremental numbered sequences with a list comprehension
Pythonic way to convert a list of integers into a string of comma-separated ranges

input = [1, 2, 3, 4, 8, 10, 11, 12, 17] 

i, ii, result = iter(input), iter(input[1:]), [[input[0]]] 
for x, y in zip(i,ii): 
    if y-x != 1: 
     result.append([y]) 
    else: 
     result[-1].append(y) 

>>> result 
[[1, 2, 3, 4], [8], [10, 11, 12], [17]] 

>>> print ", ".join("-".join(map(str,(g[0],g[-1])[:len(g)])) for g in result) 
1-4, 8, 10-12, 17 

>>> [(g[0],g[-1])[:len(g)] for g in result] 
[(1, 4), (8,), (10, 12), (17,)] 
1

La pregunta es bastante antiguo, pero pensé que voy a compartir mi solución de todos modos

Suponiendo import numpy as np

a = [1,2,3,4,5,8,9,10,11,200,201,202] 

np.split(a, array(np.add(np.where(diff(a)>1),1)).tolist()[0]) 
Cuestiones relacionadas