2011-12-11 7 views
8

Estoy bastante seguro de que todos están de acuerdo en que rle es una de esas funciones "gotcha" en R. ¿Hay alguna función similar que pueda "atrapar" una "carrera" "de valores enteros adyacentes?función tipo rle que captura "run" de enteros adyacentes

Por lo tanto, si tengo un vector como éste:

x <- c(3:5, 10:15, 17, 22, 23, 35:40) 

y llamar a esa función esotérica, voy a conseguir la respuesta como ésta:

lengths: 3, 6, 1, 2, 6 
values: (3,4,5), (10,11,12... # you get the point 

No es tan difícil de escribe una función como esta, pero aun así ... ¿Alguna idea?

+1

Creo que significaba longitudes 3, 6, 1, 2, 6 ... también, ¿qué haría con C (4,4,5,6,9)? – John

+0

¡Creo que el código de los golfistas podría tener un día con este! – Spacedman

+0

posible duplicado de [detectar intervalos de las secuencias de enteros consecuentes] (http://stackoverflow.com/questions/8400901/detect-intervals-of-the-consequent-integer-secuencias) –

Respuesta

8

1) calcular los valores y luego longitudes basada en valores

s <- split(x, cumsum(c(0, diff(x) != 1))) 
run.info <- list(lengths = unname(sapply(s, length)), values = unname(s)) 

ejecutarlo usando x de la cuestión da a este:

> str(run.info) 
List of 2 
$ lengths: int [1:5] 3 6 1 2 6 
$ values :List of 5 
    ..$ : num [1:3] 3 4 5 
    ..$ : num [1:6] 10 11 12 13 14 15 
    ..$ : num 17 
    ..$ : num [1:2] 22 23 
    ..$ : num [1:6] 35 36 37 38 39 40 

2) Calcular longitudes y luego los valores basados ​​en longitudes

Aquí hay una segunda base de solución d en Gregor's length calculation:

lens <- rle(x - seq_along(x))$lengths 
list(lengths = lens, values = unname(split(x, rep(seq_along(lens), lens)))) 

3) Calcular longitudes y valores sin necesidad de utilizar otro

Éste parece ineficiente ya que calcula cada uno de lengths y values desde cero y también parece algo excesivamente complejo, pero lo hace logran obtener todo a una sola declaración, así que pensé en agregarlo también. Es básicamente una mezcla de las dos soluciones anteriores marcadas con 1) y 2) arriba. Nada realmente nuevo en relación con esos dos.

list(lengths = rle(x - seq_along(x))$lengths, 
      values = unname(split(x, cumsum(c(0, diff(x) != 1))))) 

EDIT: segundo solución Añadido.

EDIT: Se agregó la tercera solución.

+1

Muy agradable. Y si está dispuesto a usar 'rle', esto se puede simplificar a' rle (cumsum (c (0, diff (x)! = 1))) $ length' –

+0

@Josh, que solo calcula las longitudes y parece no es realmente más simple. –

+0

OK - Debería haber leído la pregunta con más cuidado, y hace que su solución sea aún más impresionante. –

5

Como dices, es bastante fácil escribir algo similar al rle. De hecho, el ajuste del código para rle añadiendo + 1 podría dar algo así como

rle_consec <- function(x) 
{ 
    if (!is.vector(x) && !is.list(x)) 
     stop("'x' must be an atomic vector") 
    n <- length(x) 
    if (n == 0L) 
    return(structure(list(lengths = integer(), values = x), 
      class = "rle_consec")) 
    y <- x[-1L] != x[-n] + 1 
    i <- c(which(y | is.na(y)), n) 
    structure(list(lengths = diff(c(0L, i)), values = x[i]), 
       class = "rle_consec") 
} 

y utilizar el ejemplo

> x <- c(3:5, 10:15, 17, 22, 23, 35:40) 
> rle_consec(x) 
$lengths 
[1] 3 6 1 2 6 

$values 
[1] 5 15 17 23 40 

attr(,"class") 
[1] "rle_consec" 

que es lo que Juan esperaba.

Puede ajustar el código aún más para dar el primero de cada subsecuencia consecutiva en lugar de la última.

6

¿Qué tal

rle(x - 1:length(x))$lengths 
# 3 6 1 2 6 

Las longitudes son los deseados, aunque estoy de supresión de una manera igualmente inteligente para obtener los valores adecuados, pero con cumsum() y el original x son muy accesibles.

Cuestiones relacionadas