3

I am stuck with question. how to join consecutive duplicate odd list and remove all but first list. I have got how to sum consecutive duplicate rows and remove all but first row (link: R sum consecutive duplicate odd rows and remove all but first). But this project, i would like to join the consecutive duplicate odd list but not all of the consecutive duplicate list.

data.table or dplyr will be fine

for example:

ia<-c(1,1,2,2,1,1,1,1)
time <- list(c(23,43),
             c(24,54,32), 
             c(23,43,232), 
             c(24,54,32),
             c(23,43,2), 
             c(24,54,32),
             c(24,54,32),
             c(24,54,32)
            )

to

res_time <- list(c(23,43,24,54,32), # 1+1
                 c(23,43,232),      # 2
                 c(24,54,32),       # 2
                 c(23,43,2,24,54,32,24,54,32,24,54,32) # 1+1+1+1
                 )

Thanks!

thothal
  • 16,690
  • 3
  • 36
  • 71
hees
  • 71
  • 5

3 Answers3

2

This "almost" gives the expected output using only base R. We create a grouping sequence using diff. To select groups alternately, we create a sequence of alternate TRUE/FALSE value recursively and based on this value we unlist and combine the list values in mapply.

pat <- cumsum(c(0, diff(ia)) != 0)

mapply(function(x, y) if(y) unlist(time[x]) else time[x], 
 split(seq_along(time), pat), rep(c(TRUE, FALSE), length.out = length(unique(pat))))


#$`0`
#[1] 23 43 24 54 32

#$`1`
#$`1`[[1]]
#[1]  23  43 232

#$`1`[[2]]
#[1] 24 54 32


#$`2`
# [1] 23 43  2 24 54 32 24 54 32 24 54 32
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
1

To get the structure which you want, you could use the following base R functions:

## use run lengths encoding to get consecutive blocks
rl <- rle(ia)$lengths
## which of these blocks appear on an odd position
is_odd <- seq_along(rl) %% 2 == 1
## which is the last index of the consecutive blocks
ends <- cumsum(rl)
## helper function: if odd combine, otherwise leave as is
combine_or_leave <- function(in_vec, is_odd) {
   if(is_odd) {
      list(unlist(in_vec))
   } else {
      in_vec
   }
}

## apply over length, indices and is_odd flags
res <- unlist(mapply(function(lens, ends, is_odd) {
    ind <- rev(seq(ends, by = -1, length.out = lens))
    combine_or_leave(time[ind], is_odd)
}, rl, ends, is_odd), recursive = FALSE)

all.equal(res, res_time)
# [1] TRUE
res

# [[1]]
# [1] 23 43 24 54 32

# [[2]]
# [1]  23  43 232

# [[3]]
# [1] 24 54 32

# [[4]]
#  [1] 23 43  2 24 54 32 24 54 32 24 54 32
thothal
  • 16,690
  • 3
  • 36
  • 71
0

Also the following loop approach yields the desired outcome:

result <- {
  splitTime <- split(time, with(rle(ia), rep(seq_along(values), lengths)))
  result <- list()
  for(i in seq_along(splitTime)) {
    if(as.integer(names(splitTime)[i]) %% 2 == 0) { 
      result <- c(result, splitTime[[i]]) } else {
        result <- c(result, list(unlist(splitTime[[i]])))
      }
  }
  result
}
print(result)
#[[1]]
#[1] 23 43 24 54 32
#
#[[2]]
#[1]  23  43 232
#
#[[3]]
#[1] 24 54 32
#
#[[4]]
#[1] 23 43  2 24 54 32 24 54 32 24 54 32
Patrik_P
  • 3,066
  • 3
  • 22
  • 39