Reputation: 97
I have a sorted vector:
c(1, 10, 31, 80, 100, 120, 160)
I would like to split its elements into several groups by range, which I set to 31 in this example.
The result is like this:
[[1]] 1, 10, 31
[[2]] 80, 100
[[3]] 100, 120
[[4]] 160
The ranges in each group is less than 31. I have tried a loop, but I do not like it. Also, I tried the outer
function, where I calculated all pairwise differences:
res <- outer(vec, vec, "-")
Then filter each column by the condition > 0
and < 31
.
apply(res, 2, function(x) x[x > 0 & x < 31])
The result is not good enough though...
Upvotes: 4
Views: 403
Reputation: 2777
Here's a neat solution
x <- c(1, 10, 31, 80, 100, 120, 160)
y <- findInterval(x+30, x)
lapply(seq_along(x)[!duplicated(y)], function(z) x[z:y[z]])
#> [[1]]
#> [1] 1 10 31
#>
#> [[2]]
#> [1] 80 100
#>
#> [[3]]
#> [1] 100 120
#>
#> [[4]]
#> [1] 160
Upvotes: 1
Reputation: 26238
I think this will serve your purpose finally
First list will extract items fulfilling your condition of range, whereas final_list will remove items that are actually contained in some other items.
vec <- c(1, 10, 31, 80, 100, 120, 160)
first_list <- unique(apply(outer(vec, vec, "-"), 1, function(x){vec[(x < 31 & x >= 0)] }))
final_list <- first_list[!sapply(seq_along(first_list), function(i) max(sapply(first_list[-i],function(L) all(first_list[[i]] %in% L))))]
> final_list
[[1]]
[1] 1 10 31
[[2]]
[1] 80 100
[[3]]
[1] 100 120
[[4]]
[1] 160
Upvotes: 1