Reputation: 32548
I'm trying to see if there is a better way to split vector into list in such a way that all consecutive unique values are put in one group.
Note that the method has to work when x
is character too.
#DATA
x = c(0, 0, 0, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7)
x
#[1] 0 0 0 7 7 7 7 0 0 0 0 0 0 0 7 7 7 7
#DESIRED OUTPUT
L = list(c(0, 0, 0), c(7, 7, 7, 7), c(0, 0, 0, 0, 0, 0, 0), c(7, 7, 7, 7))
L
#[[1]]
#[1] 0 0 0
#[[2]]
#[1] 7 7 7 7
#[[3]]
#[1] 0 0 0 0 0 0 0
#[[4]]
#[1] 7 7 7 7
#CURRENT APPROACH
split_vector = 0
for (i in 2:length(x)){
split_vector[i] = ifelse(x[i] != x[i-1], max(split_vector) + 1, split_vector[i-1])
}
split(x, split_vector)
#$`0`
#[1] 0 0 0
#$`1`
#[1] 7 7 7 7
#$`2`
#[1] 0 0 0 0 0 0 0
#$`3`
#[1] 7 7 7 7
Upvotes: 1
Views: 676
Reputation: 269471
Here are some alternatives:
1) Use rle
with rep
to form a grouping vector and split on that. No packages are used.
split(x, with(rle(x), rep(seq_along(values), lengths)))
giving:
$`1`
[1] 0 0 0
$`2`
[1] 7 7 7 7
$`3`
[1] 0 0 0 0 0 0 0
$`4`
[1] 7 7 7 7
2) Using rleid
from the data.table package it is even easier:
library(data.table)
split(x, rleid(x))
Upvotes: 5
Reputation: 2434
tapply(x, cumsum(c(TRUE, diff(x) != 0)), identity)
$`1`
[1] 0 0 0
$`2`
[1] 7 7 7 7
$`3`
[1] 0 0 0 0 0 0 0
$`4`
[1] 7 7 7 7
# Character example
x <- rep(c("a", "b", "c", "a"), c(4, 3, 2, 4))
x
[1] "a" "a" "a" "a" "b" "b" "b" "c" "c" "a" "a" "a" "a"
# Character version
tapply(x, cumsum(c(TRUE, x[-1] != x[-length(x)])), identity)
$`1`
[1] "a" "a" "a" "a"
$`2`
[1] "b" "b" "b"
$`3`
[1] "c" "c"
$`4`
[1] "a" "a" "a" "a"
Upvotes: 3