Reputation: 77
I have results of a study stored in lists.
In total I have 1000 lists all of which are the same dimension.
Each list contains 39 elements which are matrices of different dimensions.
I would like to sum these list and then divide them by 1000.
I could not figure out a way to do this.
Example:
a<-matrix(0,nrow=5,ncol=6)
b<-matrix(0,nrow=2,ncol=10)
list1 <- list(a,b)
a<-matrix(0,nrow=5,ncol=6)
b<-matrix(0,nrow=2,ncol=10)
list2 <- list(a,b)
a<-matrix(0,nrow=5,ncol=6)
b<-matrix(0,nrow=2,ncol=10)
list3 <- list(a,b)
I want to add list1 + list2 + list3...list1000
and then divide each element in the final list by 1000.
Upvotes: 3
Views: 95
Reputation: 3930
I have recently implemented some recursive utility functions for that. However they don't check the preconditions (equal length, summability of the elements).
EDIT: I have fixed the issues mentioned in the comments. The for-loops are replaced by high-order functions, and the function has a better error-behaviour. The function processes also more complex list-structures e.g. lists containing other lists containing numeric elements. It's more (and more complex) than what the OP asked for, but I thought it's worth to be kept in case someone needs a recursive solution.
sum_numeric_lists <- function(...){
lists <- list(...)
if (length(unique(sapply(lists, length))) > 1) {
stop("lists are not of equal length")
}
Map(function(...) {
elems <- list(...)
if (length(unique(sapply(elems, class))) > 1) {
stop("corresponding elements have different types")
}
if (is.list(elems[[1]])) {
sum_numeric_lists(...)
} else if(is.numeric(elems[[1]])){
Reduce(`+`, elems)
} else {
warning("lists contain types other than numeric, which are preserved as NULL elements")
NULL
}
}, ...)
}
devide_numeric_list_by <- function(l, divisor){
lapply(X = l, FUN = function(elem) {
if (is.list(elem)) {
devide_numeric_list_by(elem, divisor)
} else if(is.numeric(elem)){
elem / divisor
} else {
warning("lists contain types other than numeric, which are preserved as NULL elements")
NULL
}
})
}
avg_numeric_lists <- function(...){
sum_l <- sum_numeric_lists(...)
devide_numeric_list_by(sum_l, length(list(...)))
}
Some tests:
avg_numeric_lists()
avg_numeric_lists(NULL)
avg_numeric_lists(list())
avg_numeric_lists(list(NULL))
avg_numeric_lists(list(1))
avg_numeric_lists(list(list(1)))
list1 <- list(m_first_lvl = matrix(sample(1:10, 20, replace = T), nrow=4, ncol=5),list(m_sec_lvl = matrix(sample(1:10, 6, replace = T), nrow=3, ncol=2)),"not_a_list_or_numeric",a_number = 1)
list2 <- list(m_first_lvl = matrix(sample(1:10, 20, replace = T), nrow=4, ncol=5),list(m_sec_lvl = matrix(sample(1:10, 6, replace = T), nrow=3, ncol=2)),"not_a_list_or_numeric",a_number = 2)
list3 <- list(m_first_lvl = matrix(sample(1:10, 20, replace = T), nrow=4, ncol=5),list(m_sec_lvl = matrix(sample(1:10, 6, replace = T), nrow=3, ncol=2)),"not_a_list_or_numeric",a_number = 3)
avg_numeric_lists(list1, list2, list3)
For calling it on all lists in the global environment (as suggested by rawr):
do.call(what = avg_numeric_lists, args = mget(ls(pattern = '^list\\d+$')))
Upvotes: 0
Reputation: 20811
You can use a combination of Map
and Reduce
and use mget
to collect all your lists into one list.
a<-matrix(1,nrow=5,ncol=6)
b<-matrix(10,nrow=2,ncol=10)
list1 <- list(a,b)
list2 <- list(a,b)
list3 <- list(a,b)
l <- mget(ls(pattern = '^list\\d+$'))
(fl <- Reduce(function(x, y) Map(`+`, x, y), l))
# [[1]]
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 3 3 3 3 3 3
# [2,] 3 3 3 3 3 3
# [3,] 3 3 3 3 3 3
# [4,] 3 3 3 3 3 3
# [5,] 3 3 3 3 3 3
#
# [[2]]
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 30 30 30 30 30 30 30 30 30 30
# [2,] 30 30 30 30 30 30 30 30 30 30
Map(`/`, fl, 1000)
# [[1]]
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 0.003 0.003 0.003 0.003 0.003 0.003
# [2,] 0.003 0.003 0.003 0.003 0.003 0.003
# [3,] 0.003 0.003 0.003 0.003 0.003 0.003
# [4,] 0.003 0.003 0.003 0.003 0.003 0.003
# [5,] 0.003 0.003 0.003 0.003 0.003 0.003
#
# [[2]]
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.03
# [2,] 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.03
Upvotes: 3