0

So I have this vector:

a = sample(0:3, size=30, replace = T)
 [1] 0 1 3 3 0 1 1 1 3 3 2 1 1 3 0 2 1 1 2 0 1 1 3 2 2 3 0 1 3 2

What I want to have is a list of vectors with all the elements that are separated by n 0s. So in this case, with n = 0 (there can't be any 0 between the consecutive values), this would give:

res = c([1,3,3], [1,1,1,3,3,2,1,1,3], [2,1,1,2]....)

However, I would like to control the n-parameter flexible to that if I would set it for example to 2, that something like this:

b = c(1,2,0,3,0,0,4)

would still result in a result like this

res = c([1,2,3],[4])

I tried a lot of approaches with while loops in for-loops while trying to count the number of 0s. But I just could not achieve it.

Update

I tried to post the question in a more real-world setting here: Flexibly calculate column based on consecutive counts in another column in R

Thank you all for the help. I just don't seem to manage put your help into practice with my limited knowledge..

Robin Kohrs
  • 655
  • 7
  • 17
  • 1
    To be able to reproduce your `sample` data, please use `set.seed`. That said, I think your vector 'b' is more than enough to demonstrate the problem - just use that throughout ;) Also, whenever the word 'consecutive' is used, it smells `rle`. Check it! – Henrik Mar 04 '21 at 15:38
  • 1
    This probably needs to be focused on a specific programming problem, you should add code you've tried to be [on-topic](https://stackoverflow.com/help/on-topic) on Stack Overflow. – jay.sf Mar 04 '21 at 16:12

3 Answers3

2

Here is a base R option using rle + split for general cases, i.e., values in b is not limited to 0 to 3.

with(
  rle(with(rle(b == 0), rep(values & lengths == n, lengths))),
  Map(
    function(x) x[x != 0],
    unname(split(b, cut(seq_along(b), c(0, cumsum(lengths))))[!values])
  )
)

which gives (assuming n=2)

[[1]]
[1] 1 2 3

[[2]]
[1] 4

If you have values within ragne 0 to 9, you can try the code below

lapply(
  unlist(strsplit(paste0(b, collapse = ""), strrep(0, n))),
  function(x) {
    as.numeric(
      unlist(strsplit(gsub("0", "", x), ""))
    )
  }
)

which also gives

[[1]]
[1] 1 2 3

[[2]]
[1] 4
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
1

I also wanted to paste a somehow useful solution with the function SplitAt from DescTools:

SplitAt(a, which(a==0)) %>% lapply(., function(x) x[which(x != 0)])

where a is your intial vector. It gives you a list where every entry contains the pair of numbers between zeros:

1st solution

If you than add another SplitAt with empty chars, you can create sublist after sublist and split it in as many sublists as you want: e.g.:

n <- 4
SplitAt(a, which(a==0)) %>% lapply(., function(x) x[which(x != 0)]) %>% SplitAt(., n)

gives you:

enter image description here

Patrick Bormann
  • 729
  • 6
  • 16
0
set.seed(1)
a <- sample(0:3, size=30, replace = T)
a
[1] 0 3 2 0 1 0 2 2 1 1 2 2 0 0 0 1 1 1 1 2 0 2 0 0 0 0 1 0 0 1

a2 <- paste(a, collapse = "") # Turns into a character vector, making it easier to handle patterns.
a3 <- unlist(strsplit(a2, "0")) # Change to whatever pattern you want, like "00".
a3 <- a3[a3 != ""] # Remove empty elements
a3 <- as.numeric(a3) # Turn back to numeric
a3
[1]     32      1 221122  11112      2      1      1
Phil
  • 7,287
  • 3
  • 36
  • 66