95

I need to convert a multi-row two-column data.frame to a named character vector. My data.frame would be something like:

dd = data.frame(crit = c("a","b","c","d"), 
                name = c("Alpha", "Beta", "Caesar", "Doris")
                )

and what I actually need would be:

whatiwant = c("a" = "Alpha",
              "b" = "Beta",
              "c" = "Caesar",
              "d" = "Doris")
kRazzy R
  • 1,561
  • 1
  • 16
  • 44
Stefan F
  • 2,573
  • 1
  • 17
  • 19

6 Answers6

91

Use the names function:

whatyouwant <- as.character(dd$name)
names(whatyouwant) <- dd$crit

as.character is necessary, because data.frame and read.table turn characters into factors with default settings.

If you want a one-liner:

whatyouwant <- setNames(as.character(dd$name), dd$crit)
Roland
  • 127,288
  • 10
  • 191
  • 288
73

You can also use deframe(x) from the tibble package for this.

tibble::deframe()

It converts the first column to names and second column to values.

merv
  • 67,214
  • 13
  • 180
  • 245
John Waller
  • 2,257
  • 4
  • 21
  • 26
  • 8
    Thank you John! I am amazed that after years of using the tidyverse I still learn about functions that are so useful. I wish I knew about this a long time ago. I guess I'm always a student. – HowYaDoing Oct 08 '19 at 13:47
  • 7
    For anyone coming to this post asking the inverse question - *How do I convert a named vector to a two-column data frame?* - the answer is `tibble::enframe()` – acvill Dec 10 '21 at 16:28
26

Here is a very general, easy, tidy way:

library(dplyr)

iris %>%
  pull(Sepal.Length, Species)

The first argument is the values, the second argument is the names.

stevec
  • 41,291
  • 27
  • 223
  • 311
25

You can make a vector from dd$name, and add names using names(), but you can do it all in one step with structure():

whatiwant <- structure(as.character(dd$name), names = as.character(dd$crit))
alexwhan
  • 15,636
  • 5
  • 52
  • 66
8

For variety, try split and unlist:

unlist(split(as.character(dd$name), dd$crit))
#        a        b        c        d 
#  "Alpha"   "Beta" "Caesar"  "Doris" 
A5C1D2H2I1M1N2O1R2T1
  • 190,393
  • 28
  • 405
  • 485
  • 1
    It should be pointed out that this makes duplicated names unique by appending a number to them. It's also not very efficient with big vectors. – Roland Oct 09 '13 at 08:14
3

There's also a magrittr solution to this via the exposition pipe (%$%):

library(magrittr)

dd %$% set_names(as.character(name), crit)

Minor advantage over tibble::deframe is that one doesn't have to have exactly a two-column frame/tibble as argument (i.e., avoid a select(value_col, name_col) %>%).

Note that the magrittr::set_names versus base::setNames is exchangeable. I simply prefer the former since it matches "set_(col|row)?names".

merv
  • 67,214
  • 13
  • 180
  • 245