I have a set of integer intervals in some range, e.g. 1-20, and I would like to generate complementary, contiguous intervals to them, like so:
intervals <- list(3:6, 10:11, 19:20)
complementary_intervals <- list(1:2, 7:9, 12:18)
Alternatively, I'll have a dataframe/tibble of start and end integers:
library(tidyverse)
intervals <- tribble(
~start, ~end,
3, 6,
10, 11,
19, 20
)
How can I find the complementary intervals? I've tried using set_diff
to generate the integers not included in the intervals, but then I'm stuck finding contiguous intervals from those.
Following @Maël's suggestion in the comments, I post my comment as an answer.
Try
# data
intervals = list(3:6, 10:11, 19:20)
complementary_intervals = list(1:2, 7:9, 12:18)
# task
x = setdiff(1L:20L, unlist(intervals))
split(x, cumsum(c(1L, diff(x) != 1L)))
#> $`1`
#> [1] 1 2
#>
#> $`2`
#> [1] 7 8 9
#>
#> $`3`
#> [1] 12 13 14 15 16 17 18
To check the result:
y = split(x, cumsum(c(1L, diff(x) != 1L)))
mapply(FUN = "%in%", complementary_intervals, y)
The two lines could be rewritten as with the base pipe operator, nothing added to the environment.
list(3:6, 10:11, 19:20) |>
{ \(.) setdiff(1L:20L, unlist(.)) }() |>
{ \(.) split(., cumsum(x = c(1L, diff(.) != 1L))) }()