2011-12-11 54 views
8

我敢肯定,你們都同意rle是R中那些「gotcha」函數之一。是否有任何類似的函數可以「捕捉」一個「run 「的相鄰整數值?rle-like函數捕捉相鄰整數的「運行」

所以,如果我有這樣一個向量:

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

而且我認爲這種深奧的功能,我會得到迴應像這樣的:

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

這並不難寫這樣的功能,但仍然...任何想法?

+1

我相信你的意思是長度爲3,6,1,2,6 ......還有,你會如何處理C(4,4,5,6,9)? – John

+0

我認爲代碼高爾夫球手可能會有這一天的一天! – Spacedman

+0

[檢測後續整數序列的間隔]的可能重複(http://stackoverflow.com/questions/8400901/detect-intervals-of-the-consequent-integer-sequences) –

回答

8

1)計算的值,然後長度基於值

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

使用x從提問運行它給出了這樣的:

> 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)計算的長度,然後值基於長度

這裏是第二個解決方案庫d上Gregor's length calculation

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

3)計算的長度和值而無需使用其他

這一個似乎低效,因爲它計算每個的lengthsvalues從頭並且它也似乎有些過於複雜,但它確實設法把它歸結爲一個單一的聲明,所以我想我也會添加它。它基本上只是前面兩個標記爲1)和2)的解決方案的混合體。相對於這兩者來說,這沒什麼新意。

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

編輯:添加第二個解決方案。

編輯:增加了第三種解決方案。

+1

非常好。如果你願意使用'rle',這可以簡化爲'rle(cumsum(c(0,diff(x)!= 1)))$ length' –

+0

@Josh,它只計算長度,似乎不是很簡單。 –

+0

好的 - 我應該更仔細地閱讀這個問題,這讓您的解決方案更加令人印象深刻。 –

5

正如你所說,很容易寫出類似rle的東西。事實上,加入+ 1調整代碼rle可能會給像

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

,並使用你的榜樣

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

這就是約翰的預期。

您可以進一步調整代碼以給出每個連續子序列的第一個,而不是最後一個。

6

找到它的長度如何

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

是你想要什麼,雖然我消隱同樣聰明的方式來獲取正確的值,但cumsum()和原來的x他們很方便。