Jonathan
Jonathan

Reputation: 15

Applying a split on a nested list based on index of element in R

I am new to R and after some research I couldn't find a solution to my problem.

I am trying to split a nested list based on the index of the character (if an index is even, it is stored in 'even', if an index is odd, it is stored in 'odd'). I have managed to solve this problem using a for loop, but do not wish to proceed with this approach as the data I am trying to parse is quite large.

Without a nested list, the following statements work (as it is a simple list of characters). The split I am using is splitting the elements of the parent list instead of the nested list.

odd <- x[(2*(1:(length(x)/2))-1)] even <- x[2*(1:(length(x)/2))]

This is a code snippet of an example I generated to better explain the problem

test <- vector(mode = "list",length = 0)
new <- "a b c d e f g h i g k"
new <- strsplit(new, split = " ")
new1 <- "l m n o p q"
new1 <- strsplit(new1, split = " ")
new2 <- "q s t u v w x"
new2 <- strsplit(new2, split = " ")
new3 <- "y z"
new3 <- strsplit(new3, split = " ")
test <- c(test, new,new1,new2,new3)

odd <- test[(2*(1:(length(test)/2))-1)]
even <- test[2*(1:(length(test)/2))]

The Desired result is as follows:

>odd
[[1]]
[1] "a" "c" "e" "g" "i" "k"
[[2]]
[1] "l" "n" "p"
[[3]]
[1] "q" "t" "v" "x"
[[4]]
[1] "y"

>even
[[1]]
[1] "b" "d" "f" "h" "j"
[[2]]
[1] "m" "o" "q"
[[3]]
[1] "s" "u" "w"
[[4]]
[1] "z"

The obtained result using the code shown above:

>odd
[[1]]
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k"
[[2]]
[1] "q" "s" "t" "u" "v" "w" "x"
>even
[[1]]
[1] "l" "m" "n" "o" "p" "q"
[[2]]
[1] "y" "z"

Would really appreciate it if anyone can help me out with the problem.

Upvotes: 0

Views: 311

Answers (2)

alistaire
alistaire

Reputation: 43344

One option is to split each element and then use purrr::transpose to rearrange your list into an even and odd list:

test <- list(c("a", "b", "c", "d", "e", "f", "g", "h", "i", "g", "k"), 
             c("l", "m", "n", "o", "p", "q"),
             c("q", "s", "t", "u", "v", "w", "x"), 
             c("y", "z"))

library(purrr)

test_split <- test %>% 
    map(~split(.x, rep_along(.x, c('odd', 'even')))) %>% 
    # just `map(split, c('odd', 'even'))` will work, but warns about recycling
    transpose()

str(test_split)
#> List of 2
#>  $ even:List of 4
#>   ..$ : chr [1:5] "b" "d" "f" "h" ...
#>   ..$ : chr [1:3] "m" "o" "q"
#>   ..$ : chr [1:3] "s" "u" "w"
#>   ..$ : chr "z"
#>  $ odd :List of 4
#>   ..$ : chr [1:6] "a" "c" "e" "g" ...
#>   ..$ : chr [1:3] "l" "n" "p"
#>   ..$ : chr [1:4] "q" "t" "v" "x"
#>   ..$ : chr "y"

Upvotes: 1

G. Grothendieck
G. Grothendieck

Reputation: 269714

Use the fact that short logical vectors recycle:

odd <- lapply(test, "[", c(TRUE, FALSE))
even <- lapply(test, "[", c(FALSE, TRUE))

Upvotes: 2

Related Questions