63

Is there a way to use mapply on two vectors to construct a named list? The first vector would be of type character and contain the names used for the list while the second contains the values.

So far, the only solution I have is:

> dummyList = list()
> addToList <- function(name, value) {
+ dummyList[[name]] <- value
+ }
> mapply(addToList, c("foo", "bar"), as.list(c(1, 2))
$foo
`1`

$bar
`2`

This seems like a rather contrived solution, but I can't figure out how to do it otherwise. The problems I have with it are:

  1. It requires the creation of dummyList even though dummyList is never changed and is an empty list after the call to mapply.

  2. If the numeric vector, c(1, 2), is not converted to a list, then the result of the call to mapply is a named vector of doubles.

To get around problem 2, I can always just call mapply on two vectors and then call as.list on the result, but it seems like there should be a way to directly create a list with the values being in a vector.

smci
  • 32,567
  • 20
  • 113
  • 146
Jon Claus
  • 2,862
  • 4
  • 22
  • 33
  • Related: Create a tibble (instead of a named list) directly in code, with attribute names and values side-by-side, as any language of 2020 should be able to: https://stackoverflow.com/questions/58427326/ ... proper in-code definitions of maps: it should not be hard. – David Tonhofer Feb 26 '20 at 14:04

3 Answers3

117

You can use setNames()

setNames(as.list(c(1, 2)), c("foo", "bar"))

(for a list) or

setNames(c(1, 2), c("foo", "bar"))

(for a vector)

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
11

What I propose is made in 2 steps, and it's quite straightforward, so maybe it's easier to understand:

test_list <- list(1, 2)
names(test_list) <- c("foo", "bar")

What @ben-bolker proposes works, but just wanted to share an alternative, in case you prefer it.

Happy coding!

Unai Sanchez
  • 496
  • 1
  • 6
  • 14
9

I share Ben's puzzlement about why you might want to do this, and his recommendation.

Just for curiosity's sake, there is a sort of "hidden" feature in mapply that will allow this:

x <- letters[1:2]
y <- 1:2
mapply(function(x,y) { y }, x, y, SIMPLIFY = FALSE,USE.NAMES = TRUE)
$a
[1] 1

$b
[1] 2

Noting that the documentation for USE.NAMES says:

USE.NAMES logical; use names if the first ... argument has names, or if it is a character vector, use that character vector as the names.

smci
  • 32,567
  • 20
  • 113
  • 146
joran
  • 169,992
  • 32
  • 429
  • 468
  • 1
    I don't think this is such a puzzling use case, just a degenerate one. I needed to combine two double arrays each with some kind of row.names column that didn't get automatically picked up by USE.NAMES, so I had to pass in row.names(x) manually as an argument to the function which doesn't get used: `f = function(n, x, y) { if (y > 0) { -1 * x } else { x } }; r = mapply(f, row.names(x), x, y, SIMPLIFY=F, USE.NAMES=T)`. A `data.frame(unlist(r))` finished the job. Thanks for pointing out this feature! – Matt Chambers Apr 07 '14 at 21:11