I have this list in R
> test
[[1]]
[[1]]$right
[1] FALSE
[[1]]$left
[1] FALSE
[[2]]
[[2]]$right
[1] TRUE
[[2]]$left
[1] FALSE
which can quickly be created with this dput
list(list(right = FALSE, left = FALSE), list(right = TRUE, left = FALSE))
Now I want to sum up the right
and the left
elements in each element of the test
-list, so that I end up with a list of two elements like this:
> res
$right
[1] 1
$left
[1] 0
I thought R's Reduce
would be a good option for that (although I'm open for any advice), but I could not figure out the code. I tried the following, yet it did not work...
Reduce(function(x){
r = sum(x[["right"]])
l = sum(x[["left"]])
v = list(r, v)
}, test)
I get this error
Error in f(init, x[[i]]) : unused argument (x[[i]])
And I think I am having some misconception in my head...
CodePudding user response:
You could unlist
the lists and coerce rowSums
as.list
, which might be more efficient.
as.list(rowSums(sapply(test, unlist)))
# $right
# [1] 1
#
# $left
# [1] 0
Data:
test <- list(list(right=FALSE, left=FALSE), list(right=TRUE, left=FALSE))
CodePudding user response:
Using purrr
library(purrr)
sides <- c("left", "right")
setNames(sides, sides) |>
map(~(map_int(test, chuck, .x))) |>
map(reduce, ` `)
##> $left
##> [1] 0
##>
##> $right
##> [1] 1
CodePudding user response:
Reduce expects a function that accepts two arguments. It will get the result of the previous value of Reduce
and a new element from the vector you pass to Reduce
Reduce(\(x,y) list(left = x$left y$left, right = x$right y$right), test)
Personally, I would use sapply
(or Map
if you want) to first get the left
/right
elements and then pass those to sum
:
sapply(test, \(x) x$left) |> sum()
A version with Map
and Reduce
would be:
Map(\(x) x$left, test) |> Reduce(f = \(x, y) x y)
or
Map(\(x) x$left, test) |> Reduce(f = ` `)
CodePudding user response:
Since you need to aggregate per names, you can unlist
and use tapply
to sum by names:
ll <- list(list(right = FALSE, left = FALSE), list(right = TRUE, left = FALSE))
un <- unlist(ll)
tapply(un, names(un), FUN = sum)
# left right
# 0 1
You can transpose first:
purrr::transpose(ll) |>
lapply(Reduce, f = sum)
# $right
# [1] 1
#
# $left
# [1] 0