有没有办法动态访问数组维度(理想情况下无需重塑)?我有一个 n 维数组arr以及一个命名的维度顺序vals。的维度数量arr和的顺序都vals可能发生变化。我总是想访问等于arr的维度的第一个条目。在下面我提供了三个例子来说明我想要什么:valsB

#Example 1
vals = c("A","B","C")
idx = grep("B",vals)
arr = array(runif(5^3), dim = c(5,5,5))

arr[,1,] # B is in second dimension

#Example 2
vals = c("A","C","B","D")
idx = grep("B",vals)
arr = array(runif(5^4), dim = c(5,5,5,5))

arr[,,1,] #B is in third dimension

#Example 3
vals = c("B","A","C","D","E")
idx = grep("B",vals)
arr = array(runif(5^5), dim = c(5,5,5,5,5))

arr[1,,,,] #B is in first dimension

我根本不知道该如何处理这个问题。

1

  • 1
    可能相关:


    – 


5 个回答
5

我认为最简单、最有效的方法是使用asplit

asplit(arr, idx)[[1]]

其他选择


您也可以尝试apply以下方法

array(apply(arr, idx, c)[, 1], dim(arr)[-idx])

并验证它,例如

> set.seed(0)

> vals <- c("B", "A", "C", "D", "E")

> idx <- grep("B", vals)

> arr <- array(runif(5^5), dim = c(5, 5, 5, 5, 5))

> a <- arr[1, , , , ] # B is in first dimension

> b <- array(apply(arr, idx, c)[, 1], dim(arr)[-idx])

> all.equal(a, b)
[1] TRUE

如果你对它的索引逻辑感到困扰apply,你可以像这样解析字符串

b <- eval(str2lang(sprintf("arr[%s]", toString(replace(rep("", length(dim(arr))), idx, "1")))))

你可以获得

> all.equal(a, b)
[1] TRUE

1

  • asplit非常简洁,但eval这里的解决方案似乎运行得更快。


    – 

像这样(使用valsarr来自你的例子)?


    the_letter <- 'B'
    
    
    picklist <- Map(vals, f = \(val) ifelse(val == the_letter, 1, TRUE))
    do.call(`[`, c(list(x = arr), picklist))

您可以创建一个文本并对其进行评估:例如

cmd <- sprintf("arr[%s]", paste(ifelse(vals == "B", "1", ""), collapse = ","))
cmd
[1] "arr[,1,]"
eval(parse(text = cmd))

1

  • 啊,谢谢!我eval()以前试过,但我认为我用错了(没有这个parse()功能)。


    – 

do.call

do.call(`[`, c(list(arr), replace(as.list(rep(TRUE, length(dim(arr)))),
                                    grep("B", vals), 1)))

#Example 1
vals = c("A","B","C")
idx = grep("B",vals)
arr = array(runif(5^3), dim = c(5,5,5))
identical(
  do.call(`[`, c(list(arr), replace(as.list(rep(TRUE, length(dim(arr)))),
                                    grep("B", vals), 1))),
  arr[,1,] # B is in second dimension
)
#> [1] TRUE


#Example 2
vals = c("A","C","B","D")
idx = grep("B",vals)
arr = array(runif(5^4), dim = c(5,5,5,5))
identical(
  do.call(`[`, c(list(arr), replace(as.list(rep(TRUE, length(dim(arr)))),
                                    grep("B", vals), 1))),
  arr[,,1,] #B is in third dimension
)
#> [1] TRUE

#Example 3
vals = c("B","A","C","D","E")
idx = grep("B",vals)
arr = array(runif(5^5), dim = c(5,5,5,5,5))
identical(
  do.call(`[`, c(list(arr), replace(as.list(rep(TRUE, length(dim(arr)))),
                                    grep("B", vals), 1))),
  arr[1,,,,] #B is in first dimension
)
#> [1] TRUE

apply对不对应于 B 的索引使用每个索引中的第一个。这很简洁,并且确实涉及显式重塑。

apply(arr, which(vals != "B"), head, 1)

测试

set.seed(123)
vals = c("A","B","C")
arr = array(runif(5^3), dim = c(5,5,5))
identical(apply(arr, which(vals != "B"), head, 1), arr[,1,])
## [1] TRUE

set.seed(123)
vals = c("A","C","B","D")
arr = array(runif(5^4), dim = c(5,5,5,5))
identical(apply(arr, which(vals != "B"), head, 1), arr[,,1,])
## [1] TRUE

set.seed(123)
vals = c("B","A","C","D","E")
arr = array(runif(5^5), dim = c(5,5,5,5,5))
identical(apply(arr, which(vals != "B"), head, 1), arr[1,,,,])
## [1] TRUE