我们可以使用outer(x, y, FUN)
。 x
和y
不需要是像数值向量/矩阵那样的“数字”输入;像“list”/“矩阵列表”这样的矢量输入也是允许的。
例如,我们用
z <- outer(lst, lst, FUN = Vectorize("%in%", SIMPLIFY = FALSE, USE.NAMES = FALSE))
# vec1 vec2 vec3 vec4
#vec1 Logical,2 Logical,2 Logical,2 Logical,2
#vec2 Logical,3 Logical,3 Logical,3 Logical,3
#vec3 Logical,4 Logical,4 Logical,4 Logical,4
#vec4 Logical,5 Logical,5 Logical,5 Logical,5
由于"%in%"
本身不是矢量申请配对"%in%"
操作,我们使用Vectorized("%in%")
。我们还需要SIMPLIFY = FALSE
,以便FUN
为每对(x[[i]], y[[j]])
返回一个长度为1的列表。这一点很重要,因为outer
作品,如:
y[[4]] | FUN(x[[1]], y[[4]]) FUN(x[[2]], y[[4]]) FUN(x[[1]], y[[4]]) FUN(x[[2]], y[[4]])
y[[3]] | FUN(x[[1]], y[[3]]) FUN(x[[2]], y[[3]]) FUN(x[[1]], y[[3]]) FUN(x[[2]], y[[4]])
y[[2]] | FUN(x[[1]], y[[2]]) FUN(x[[2]], y[[2]]) FUN(x[[1]], y[[2]]) FUN(x[[2]], y[[4]])
y[[1]] | FUN(x[[1]], y[[1]]) FUN(x[[2]], y[[1]]) FUN(x[[1]], y[[1]]) FUN(x[[2]], y[[4]])
------------------- ------------------- ------------------- -------------------
x[[1]] x[[2]] x[[3]] x[[4]]
必须确信length(FUN(x, y)) == length(x) * length(y)
。虽然如果SIMPLIFY = FALSE
,这并不一定成立。
以上结果z
是“矩阵列表”,其中class(z)
为“矩阵”,但typeof(z)
为“列表”。请阅读Why is this matrix not numeric?了解更多信息。
如果我们想进一步施加一定的汇总函数的z
每个元素,我们可以使用lapply
。这里我会举两个例子。
实施例1:应用any()
由于any(a %in% b)
是any(b %in% a)
为相同的,即,操作是对称的,我们只需要具有z
下三角的工作:
lz <- z[lower.tri(z)]
lapply
返回一个未命名的列表,但为了便于阅读,我们需要一个命名列表。我们可以利用矩阵索引(i, j)
姓名:
ind <- which(lower.tri(z), arr.ind = TRUE)
NAME <- paste(ind[,1], ind[,2], sep = ":")
any_lz <- setNames(lapply(lz, any), NAME)
#List of 6
# $ 2:1: logi FALSE
# $ 3:1: logi TRUE
# $ 4:1: logi TRUE
# $ 3:2: logi TRUE
# $ 4:2: logi FALSE
# $ 4:3: logi TRUE
Set操作像intersect
,union
和setequal
也是我们能与工作同样对称操作。
例2:应用which()
which(a %in% b)
不是对称的操作,所以我们必须用全矩阵工作。
NAME <- paste(1:nrow(z), rep(1:nrow(z), each = ncol(z)), sep = ":")
which_z <- setNames(lapply(z, which), NAME)
# List of 16
# $ 1:1: int [1:2] 1 2
# $ 2:1: int(0)
# $ 3:1: int [1:2] 1 2
# $ 4:1: int 3
# $ 1:2: int(0)
# $ 2:2: int [1:3] 1 2 3
# ...
像setdiff
这样的设置操作也是不对称的,可以类似地处理。
替代
除了使用outer()
,我们也可以使用ř表达式来获得z
上方。同样,我采取二元运算"%in%"
为例:
op <- "'%in%'" ## operator
lst_name <- names(lst)
op_call <- paste0(op, "(", lst_name, ", ", rep(lst_name, each = length(lst)), ")")
# [1] "'%in%'(vec1, vec1)" "'%in%'(vec2, vec1)" "'%in%'(vec3, vec1)"
# [4] "'%in%'(vec4, vec1)" "'%in%'(vec1, vec2)" "'%in%'(vec2, vec2)"
# ...
然后我们可以在lst
分析和评估这些表达式。我们可能会使用组合索引结果列表中的名称:
NAME <- paste(1:length(lst), rep(1:length(lst), each = length(lst)), sep = ":")
z <- setNames(lapply(parse(text = op_call), eval, lst), NAME)
# List of 16
# $ 1:1: logi [1:2] TRUE TRUE
# $ 2:1: logi [1:3] FALSE FALSE FALSE
# $ 3:1: logi [1:4] TRUE TRUE FALSE FALSE
# $ 4:1: logi [1:5] FALSE FALSE TRUE FALSE FALSE
# $ 1:2: logi [1:2] FALSE FALSE
# ...
也许不能直接适用,但在这里,在类似案件中,经典的'表/(T)crossprod'方法可以透露一些成对的关系 - 'crossprod( table(val = unlist(lst,,FALSE),vec = rep(seq_along(lst),lengths(lst))))'。尽管通过制表所有内存限制可能会造成问题 –