cbind() - how to label a vector dynamically in one line

130 Views Asked by At

Consider:

cbind("1" = 1:4)
## giving.
     1
[1,] 1
[2,] 2
[3,] 3
[4,] 4

What I am trying to achieve is replacing "1" with a function that returns a character expression, e.g.

cbind(as.character(1) = 1:4)

But this gives:

Error: unexpected '=' in "cbind(as.character(1) ="

Any idea how to do this? Preferably in base R.

Note: I like compact coding.

3

There are 3 best solutions below

2
On BEST ANSWER

Use `colnames<-`().

> `colnames<-`(cbind(1:4), 1)
     1
[1,] 1
[2,] 2
[3,] 3
[4,] 4

> `colnames<-`(matrix(0, 3, 2), 1:2)
     1 2
[1,] 0 0
[2,] 0 0
[3,] 0 0

> `colnames<-`(matrix(0, 3, 2), letters[1:2])
     a b
[1,] 0 0
[2,] 0 0
[3,] 0 0
0
On

If you want to be able to programatically generate argument names for function calls, you can use setNames on a list, which you then pass to the function using do.call:

# Programatically generates the call cbind(`1` = 1:4)
do.call('cbind', setNames(list(1:4), as.character(1)))
#>      1
#> [1,] 1
#> [2,] 2
#> [3,] 3
#> [4,] 4

Or

# Programatically generates the call data.frame(a = 1:4, b = 5:8)
do.call('data.frame', setNames(list(1:4, 5:8), c('a', 'b')))
#>   a b
#> 1 1 5
#> 2 2 6
#> 3 3 7
#> 4 4 8

Or even

# Programatically generates the call mean(1:4, na.rm = TRUE)
do.call('mean', setNames(list(1:4, TRUE), c('x', 'na.rm')))
#> [1] 2.5
0
On

You could use set_names() with data frames as well, but here is also a direct solution using tibbles instead of cbind/data frames

library(dplyr)
library(rlang)

some_letter <- function(x = 1) letters[x]

tibble(1:4) %>% 
  set_names(some_letter())
#> # A tibble: 4 × 1
#>       a
#>   <int>
#> 1     1
#> 2     2
#> 3     3
#> 4     4

Created on 2023-12-05 with reprex v2.0.2

Assigning the name programmatically directly is also possible, but the code is a little harder to read I guess. Note the := instead of =.

tibble(
  !!sym(some_letter(1)) := 1:4, 
  !!sym(some_letter(2)) := 1:4
)
#> # A tibble: 4 × 2
#>       a     b
#>   <int> <int>
#> 1     1     1
#> 2     2     2
#> 3     3     3
#> 4     4     4

tibble(!!parse_expr(some_letter()) := 1:4)
#> # A tibble: 4 × 1
#>       a
#>   <int>
#> 1     1
#> 2     2
#> 3     3
#> 4     4