Home > OS >  R: how to abind many arrays, using names stored in a character vector
R: how to abind many arrays, using names stored in a character vector

Time:12-03

I have a character vector of names of arrays in my environment. e.g.

test.list <- (paste0("test.array",1:3))

I want to use these names to abind the arrays, something like:

test.array.bind1 <- abind(test.list[1:3], along = 5)

but that gives the error:

Error in abind(test.list[1:3], along = 5) : along must be between 0 and 2

I believe it is not treating the input as the names of objects, because it works when I write the names out manually.

test.array.bind <- abind(test.array1, test.array2, test.array3, along = 5)

I tried some variations like:

test.array.bind1 <- abind(paste(test.list[1:3], sep = ","), along = 5)

but get the same error.

The closest questions I have found so far are about data.frames, and suggested solutions don't directly answer this question, but say how they should be doing their workflow differently such as loading them all in lists they can then run the functions over that they wish to. I don't think that applies here.

I could have just typed the names out several times over in the hour it has taken me to try to find the solution so far (there are many more than 3 in my real data!), but I keep coming across similar problems so I wondered if there is an automated solution.

CodePudding user response:

We need mget to get the value of the objects in a list, then use abind within do.call

library(abind)
out1 <- do.call(abind, c(mget(test.list[1:3]), along = 5))

NOTE: The [1:3] is not needed if the length of the 'test.list' vector is just 3

-testing with OP's code

> out2 <- abind(test.array1, test.array2, test.array3, along = 5)
> all.equal(out1, out2, check.attributes = FALSE)
[1] TRUE

data

test.array1 <- array(1:50, dims = c(2, 2, 2, 3, 2))
test.array2 <- array(51:100, dim = c(2, 2, 2, 3, 2))
test.array3 <- array(101:150, dim = c(2, 2, 2, 3, 2))
test.list <- paste0("test.array", 1:3)

CodePudding user response:

You can do this too

library(tidyverse)

df1 = tibble(
  id = 1:10,
  x = rnorm(10)
)

df2 = tibble(
  id = 1:10,
  x = 2,
  y = rnorm(10)
)

df3 = tibble(
  id = 1:10,
  x = 3,
  y = 2,
  z = rnorm(10)
)

env = environment()

df = tibble() %>% 
  bind_rows(env[["df1"]]) %>% 
  bind_rows(env[["df2"]]) %>% 
  bind_rows(env[["df3"]])
df

output

# A tibble: 30 x 4
      id      x     y     z
   <int>  <dbl> <dbl> <dbl>
 1     1 -1.80     NA    NA
 2     2  0.143    NA    NA
 3     3 -0.620    NA    NA
 4     4  1.25     NA    NA
 5     5 -0.502    NA    NA
 6     6 -0.954    NA    NA
 7     7  0.533    NA    NA
 8     8  2.33     NA    NA
 9     9  0.207    NA    NA
10    10  0.277    NA    NA
# ... with 20 more rows

And this way

addDf = function(df, dfnames){
  for(dfn in dfnames) df = df %>% bind_rows(env[[dfn]])
  df
}

df = tibble() %>% addDf(c("df1", "df2", "df3"))
df

output

# A tibble: 30 x 4
      id      x     y     z
   <int>  <dbl> <dbl> <dbl>
 1     1 -1.80     NA    NA
 2     2  0.143    NA    NA
 3     3 -0.620    NA    NA
 4     4  1.25     NA    NA
 5     5 -0.502    NA    NA
 6     6 -0.954    NA    NA
 7     7  0.533    NA    NA
 8     8  2.33     NA    NA
 9     9  0.207    NA    NA
10    10  0.277    NA    NA
# ... with 20 more rows
  •  Tags:  
  • r
  • Related