multiply two lists of irregular length

Viewed 42

I have lists like

a <- list(list(c(-2,1), 4:5, 2:3), list(c(0,2), c(-1,1)))
b <- list(7:9, c(5,-1))

> a
[[1]]
[[1]][[1]]
[1] -2  1

[[1]][[2]]
[1] 4 5

[[1]][[3]]
[1] 2 3


[[2]]
[[2]][[1]]
[1] 0 2

[[2]][[2]]
[1] -1  1



> b
[[1]]
[1] 7 8 9

[[2]]
[1]  5 -1

I want to multiply each of (-2, 1) from a[[1] with 7 from b[[1]] to get (-14, 7), each of (4, 5) with 8, each of (2, 3) with 9, and then each of (0, 2) with 5 and finally each of (-1, 1), with -1.

I can be sure that length(a[[i]])==length(b[[i]]) is TRUE for i=1,2 (in practice, i is way larger), so that there are the right number of entries for the desired multiplications.

However, it is not clear how many entries the a[[i]]) have (in the example, 3 for a[[1]] and 2 for a[[2]], or equivalently, how long the b[[i]] are), except that they'll have at least one entry. Hence, transforming a and b into matrices does not seem practical.

I am not sure that is relevant to the problem, but it will also be the case that we have as many entries in each of the a[[i]]) (i.e., 2) as we have a[[i]])s.

I was thinking of some combination of do.call and mapply, but could not get it to work.

2 Answers

We may indeed use mapply (and Map, which is the same as mapply but with SIMPLIFY = FALSE). Depending on the format (matrix as in @RonakShah's answer or a list as in your question), you may use

Map(mapply, a, b, MoreArgs = list(FUN = `*`))
# [[1]]
#      [,1] [,2] [,3]
# [1,]  -14   32   18
# [2,]    7   40   27
#
# [[2]]
#      [,1] [,2]
# [1,]    0    1
# [2,]   10   -1

or

Map(Map, a, b, MoreArgs = list(f = `*`))
# [[1]]
# [[1]][[1]]
# [1] -14   7
#
# [[1]][[2]]
# [1] 32 40
#
# [[1]][[3]]
# [1] 18 27
#
#
#[[2]]
# [[2]][[1]]
# [1]  0 10
#
# [[2]][[2]]
# [1]  1 -1

A tidyverse alternative to the latter is

map2(a, b, map2, `*`)

Since, you can ensure length(a[[i]])==length(b[[i]]) we can use mapply inside lapply

lapply(seq_along(a), function(x) mapply("*", a[[x]], b[[x]]))


#[[1]]
#     [,1] [,2] [,3]
#[1,]  -14   32   18
#[2,]    7   40   27

#[[2]]
#     [,1] [,2]
#[1,]    0    1
#[2,]   10   -1
Related