7

给定一个包含两个列表的列表,我试图在不使用 for 循环的情况下获得第一个列表与第二个列表的所有元素乘积的列表。例如:

> a <- list(c(1,2), c(2,3), c(4,5))
> b <- list(c(1,3), c(3,4), c(6,2))
> c <- list(a, b)

该函数应返回一个包含 9 个条目的列表,每个条目大小为 2。例如,

> answer
[[1]]
[1] 1 6

[[2]]
[1] 3 8

[[3]]
[1] 6 4

[[4]]
[1] 2 9

[[5]]
[1] 6 12

etc...

我们欢迎所有的建议!

4

4 回答 4

10

一种快速(但占用大量内存)的方法是将 mapply 机制与参数回收结合使用,如下所示:

mapply(`*`,a,rep(b,each=length(a)))

给出:

> mapply(`*`,a,rep(b,each=length(a)))
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]    1    2    4    3    6   12    6   12   24
[2,]    6    9   15    8   12   20    4    6   10

或替换ac[[1]]bc[[2]]获得相同的结果。要获取列表,请设置参数SIMPLIFY = FALSE

于 2012-05-11T13:40:42.547 回答
6

不知道这是快速还是内存密集型只是它有效,Joris Meys 的回答更有说服力:

x <- expand.grid(1:length(a), 1:length(b))
x <- x[order(x$Var1), ]    #gives the order you asked for
FUN <- function(i)  diag(outer(a[[x[i, 1]]], b[[x[i, 2]]], "*"))
sapply(1:nrow(x), FUN)     #I like this out put
lapply(1:nrow(x), FUN)     #This one matches what you asked for

编辑:既然布赖恩介绍了基准测试(我喜欢(链接)),我必须做出回应。实际上,我使用我称之为 expand.grid2 的东西有一个更快的答案,它是我从HERE偷来的原版的重量较轻的版本。我之前打算把它扔掉,但当我看到 Joris 的速度有多快时,我想为什么要这么麻烦,既短又甜又快。但是现在 Diggs 已经挖好了,我想我会expand.grid2为了教育目的把它扔在这里。

expand.grid2 <-function(seq1,seq2) {
    cbind(Var1 = rep.int(seq1, length(seq2)), 
    Var2 = rep.int(seq2, rep.int(length(seq1),length(seq2))))
}

x <- expand.grid2(1:length(a), 1:length(b))
x <- x[order(x[,'Var1']), ]    #gives the order you asked for
FUN <- function(i)  diag(outer(a[[x[i, 1]]], b[[x[i, 2]]], "*"))
lapply(1:nrow(x), FUN)

这是结果(与 Bryan 的标签相同,但 TylerEG2 使用的是expand.grid2):

Unit: microseconds
            expr      min       lq   median       uq      max
1   DiggsL(a, b) 5102.296 5307.816 5471.578 5887.516 70965.58
2   DiggsM(a, b)  384.912  428.769  443.466  461.428 36213.89
3    Joris(a, b)   91.446  105.210  123.172  130.171 16833.47
4 TylerEG2(a, b)  392.377  425.503  438.100  453.263 32208.94
5   TylerL(a, b) 1752.398 1808.852 1847.577 1975.880 49214.10
6   TylerM(a, b) 1827.515 1888.867 1925.959 2090.421 75766.01
7 Wojciech(a, b) 1719.740 1771.760 1807.686 1924.325 81666.12

如果我采取订购步骤,我可以更加尖叫,但它仍然与 Joris 的答案不相近。

在此处输入图像描述

于 2012-05-11T14:01:27.653 回答
2

将其他答案中的想法汇总在一起,我将再添加一条线来取乐:

do.call(mapply, c(FUN=`*`, as.list(expand.grid(b, a))))

这使

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]    1    3    6    2    6   12    4   12   24
[2,]    6    8    4    9   12    6   15   20   10

如果您确实需要您提供的格式,那么您可以使用该plyr库将其转换为:

library("plyr")
as.list(unname(alply(do.call(mapply, c(FUN=`*`, as.list(expand.grid(b, a)))), 2)))

这使

[[1]]
[1] 1 6

[[2]]
[1] 3 8

[[3]]
[1] 6 4

[[4]]
[1] 2 9

[[5]]
[1]  6 12

[[6]]
[1] 12  6

[[7]]
[1]  4 15

[[8]]
[1] 12 20

[[9]]
[1] 24 10

只是为了好玩,基准测试:

Joris <- function(a, b) {
    mapply(`*`,a,rep(b,each=length(a)))
}

TylerM <- function(a, b) {
    x <- expand.grid(1:length(a), 1:length(b))
    x <- x[order(x$Var1), ]    #gives the order you asked for
    FUN <- function(i)  diag(outer(a[[x[i, 1]]], b[[x[i, 2]]], "*"))
    sapply(1:nrow(x), FUN)
}

TylerL <- function(a, b) {
    x <- expand.grid(1:length(a), 1:length(b))
    x <- x[order(x$Var1), ]    #gives the order you asked for
    FUN <- function(i)  diag(outer(a[[x[i, 1]]], b[[x[i, 2]]], "*"))
    lapply(1:nrow(x), FUN)
}

Wojciech <- function(a, b) {
    # Matrix with indicies for elements to multiply
    G <- expand.grid(1:3,1:3)

    # Coversion of G to list
    L <- lapply(1:nrow(G),function(x,d=G) d[x,])

    lapply(L,function(i,x=a,y=b) x[[i[[2]]]]*y[[i[[1]]]])
}

DiggsM <- function(a, b) {
    do.call(mapply, c(FUN=`*`, as.list(expand.grid(b, a))))
}

DiggsL <- function(a, b) {
    as.list(unname(alply(t(do.call(mapply, c(FUN=`*`, as.list(expand.grid(b, a))))), 1)))
}

和基准

> library("rbenchmark")
> benchmark(Joris(b,a),
+           TylerM(a,b),
+           TylerL(a,b),
+           Wojciech(a,b),
+           DiggsM(a,b),
+           DiggsL(a,b),
+           order = "relative", 
+           replications = 1000,
+           columns = c("test", "elapsed", "relative"))
            test elapsed relative
1    Joris(b, a)    0.08    1.000
5   DiggsM(a, b)    0.26    3.250
4 Wojciech(a, b)    1.34   16.750
3   TylerL(a, b)    1.36   17.000
2   TylerM(a, b)    1.40   17.500
6   DiggsL(a, b)    3.49   43.625

并表明它们是等价的:

> identical(Joris(b,a), TylerM(a,b))
[1] TRUE
> identical(Joris(b,a), DiggsM(a,b))
[1] TRUE
> identical(TylerL(a,b), Wojciech(a,b))
[1] TRUE
> identical(TylerL(a,b), DiggsL(a,b))
[1] TRUE
于 2012-05-11T20:38:26.767 回答
1
# Your data
a <- list(c(1,2), c(2,3), c(4,5))
b <- list(c(1,3), c(3,4), c(6,2))

# Matrix with indicies for elements to multiply
G <- expand.grid(1:3,1:3)

# Coversion of G to list
L <- lapply(1:nrow(G),function(x,d=G) d[x,])

lapply(L,function(i,x=a,y=b) x[[i[[2]]]]*y[[i[[1]]]])
于 2012-05-11T20:17:05.030 回答