2013-05-28 7 views
5

データをいくつかのテストに合格する連続した行のグループに分割したいとします。ここでは例です:(boolean)を連続シーケンスに分割する

set.seed(1) 
n <- 29 
ok <- sample(c(TRUE,FALSE),n,replace=TRUE,prob=c(.7,.3)) 

vec <- (1:n)[ok] 
# [1] 1 2 3 5 8 9 10 11 12 13 14 16 19 22 23 24 25 26 27 28 

所望の出力は、 "VECは、" 連続した配列にグループ化されています

out <- list(1:3,5,8:14,16,19,22:28) 

これは動作します:

nv <- length(vec) 

splits <- 1 + which(diff(vec) != 1) 
splits <- c(1,splits,nv+1) 
nsp <- length(splits) 

out <- list() 
for (i in 1:(nsp-1)){ 
    out[[i]] <- vec[splits[i]:(splits[i+1]-1)] 
} 

私がベースでクリーンな方法があると推測していますR ...?私はまだ私がSOに見てきたrlecumsumトリックと熟達していないよ...ここ

答えて

6

cumsum "トリック" はあなたのためです:

split(vec, cumsum(c(1, diff(vec)) - 1)) 

更新

ここれますバージョンsplit(vec, cumsum(c(0, diff(vec) > 1)))を使用した簡単な例を各ステップごとに示します。

vec <- c(1:3,7:9)   # 1 2 3 7 8 9 (sample with two contiguous sequences) 
diff(vec)     # 1 1 4 1 1 (lagged difference) 
diff(vec) > 1    # F F T F F (not contiguous where diff > 1) 
          # 0 0 1 0 0 (numeric equivalent for T/F) 
c(0, diff(vec) > 1)   # 0 0 0 1 0 0 (pad with 0 to align with original vector) 
cumsum(c(0, diff(vec) > 1)) # 0 0 0 1 1 1 (cumulative sum of logical values) 

groups <- cumsum(c(0, diff(vec) > 1)) # 0 0 0 1 1 1 

sets <- split(vec, groups) # split into groups named by cumulative sum 

sets 
# $`0` 
# [1] 1 2 3 
# 
# $`1` 
# [1] 7 8 9 

何らかの理由で出力したい場合:

# Create strings representing each contiguous range 
set_strings <- sapply(sets, function(x) paste0(min(x),":",max(x))) 

set_strings 
#  0  1 
# "1:3" "7:9" 

# Print out a concise representation of all contiguous sequences 
print(paste0(set_strings,collapse=",")) 

# [1] "1:3,7:9" 
+0

ありがとうございました。あなたの解を解いた後、私はこの形式が好きです: 'split(vec、cumsum(c(0、diff(vec)> 1))')。 – Frank

関連する問題