我們可以使用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))))'。儘管通過製表所有內存限制可能會造成問題 –