Search code examples
rvectorcombinationspermutationmultiplication

How to calculate the product from combinations of several vectors in R?


I feel it hard to give an accurate title, though I have tried my best. Here's my problem.

a = 1/(1:10)
b = 3/(1:10)
c = 1/(1:5)
d = 1/(1:11)

I would like to get a vector e, such that e consists of the product calculated from the combinations of values chosen from a, b, c and d.

For example, supposing there are two vectors {1, 2} and {3, 4}, I would like to get a vector like this {1 * 3, 1 * 4, 2 * 3, 2 * 4} = {3, 4, 6, 8}.

Thanks in advance!


Solution

  • The expand.grid solution is OK, but in mathematics there is an elegant Kronecker product.

    R has a function kronecker, but it takes two vectors at a time, so we need Reduce for a recursive application:

    oo <- Reduce(kronecker, list(a, b, c, d))
    

    Alternatively, use outer (the workhorse of kronecker):

    rr <- Reduce(outer, list(a, b, c, d))
    

    This is more user-friendly, as rr[i, j, u, v] gives you a[i] * b[j] * c[u] * d[v].


    Remark 1

    Note that elements in oo and rr differ in order. Because for two vectors a and b:

    kronecker(a, b)  ## a[1] * b, a[2] * b ...
    outer(a, b)      ## a * b[1], a * b[2] ...
    

    Thus the following use of kronecker produces a result identical to rr.

    zz <- Reduce(kronecker, list(d, c, b, a))
    dim(zz) <- c(length(a), length(b), length(c), length(d))
    

    Remark 2

    The method can be adapted to do a[i] + b[j] + c[u] + d[v], by replacing the default operation "*" in outer and kronecker to "+". For example:

    Reduce(function (x, y) outer(x, y, "+"), list(a, b, c, d))
    

    Remark 3

    johannes's answer can be improved. That row-wise application of apply is a performance killer. We can do the following to get a result consistent with rr.

    xx <- Reduce("*", expand.grid(a, b, c, d))
    dim(xx) <- c(length(a), length(b), length(c), length(d))