2011-12-11 11 views
8

Jestem pewien, że wszyscy zgadzają się, że rle jest jedną z tych funkcji "dostań" w R. Czy istnieje jakaś podobna funkcja, która może "złapać" bieg " "sąsiednich wartości całkowitych?Funkcja podobna do rle, która przechwytuje "bieg" sąsiednich liczb całkowitych

Więc jeśli mam wektor jak ten:

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

i wzywam, że funkcja ezoteryczny, dostanę odpowiedź jak ten:

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

To nie jest takie trudne napisać taką funkcję, ale nadal ... jakieś pomysły?

+1

Sądzę, że miałeś na myśli długość 3, 6, 1, 2, 6 ... także, co byś zrobił z C (4,4,5,6,9)? – John

+0

Podejrzewam, że golfiści kodu mogą mieć dzień z tym! – Spacedman

+0

możliwy duplikat [wykrycia interwałów kolejnych sekwencji całkowitych] (http://stackoverflow.com/questions/8400901/detect-intervals-of-the-consequent-integer-sequences) –

Odpowiedz

8

1) Obliczenie wartości i długościach na podstawie wartości

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

włączonego za pomocą x od kwestii, daje to:

> 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) Obliczenie długości i wartości na podstawie długości

Oto druga podstawa rozwiązania D Na Gregor's length calculation:

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

3) Obliczenie długości i wartości bez użycia innych

ten wydaje nieefektywne, ponieważ oblicza każdy lengths i values od zera, a także wydaje się nieco zbyt skomplikowane, lecz nie udaje mi się to wszystko sprowadzić do pojedynczego zdania, więc pomyślałem, że też je dodam. Jest to po prostu mieszanka dwóch poprzednich rozwiązań oznaczonych 1) i 2) powyżej. Nic naprawdę nowego w stosunku do tych dwóch.

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

EDIT: Dodano drugie rozwiązanie.

EDYCJA: Dodano trzecie rozwiązanie.

+1

Bardzo ładnie. A jeśli chcesz użyć 'rle', możesz to uprościć do' rle (cumsum (c (0, diff (x)! = 1)) $ length' –

+0

@Josh, To tylko oblicza długości i wydaje się naprawdę nie jest prostsze. –

+0

OK - powinienem był przeczytać to pytanie dokładniej, a to sprawia, że ​​twoje rozwiązanie jest jeszcze bardziej imponujące. –

5

Jak można powiedzieć, łatwo jest napisać coś podobnego do rle. Rzeczywiście, dostosowując kod rle dodając + 1 może dać coś podobnego

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") 
} 

i za pomocą przykładu

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

która jest, co Jan oczekiwano.

Można dostosować kod, aby podać pierwszy z kolejnych podsekwencji zamiast ostatniego.

6

Jak o

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

Długości to, co chcesz, choć jestem na wygaszania równie sprytny sposób, aby uzyskać odpowiednie wartości, ale i ze cumsum() oryginalny x są bardzo dostępne.

Powiązane problemy