5

I have the dataframe of the following type

df <- tibble::tribble(~x,
                      c("A", "B"),
                      c("A", "B", "C"),
                      c("A", "B", "C", "D"),
                      c("A", "B"))

and vectors like these

vec1 <- c("A", "B")
vec2 <- c("A", "B", "C")
vec3 <- c("A", "B", "C", "D")

I want to mutate a variable y that shows which row has which vector. I tried the following, but getting the empty y variable with the warning: "longer object length is not a multiple of shorter object length"

df_new <- df %>%
  mutate(y = case_when(x == vec1 ~ "vec1",
                       x == vec2 ~ "vec2",
                       x == vec2 ~ "vec3"))

The desired output is

df_new <- tibble::tribble(~x,                      ~y,
                          c("A", "B"),             "vec1",
                          c("A", "B", "C"),        "vec2",
                          c("A", "B", "C", "D"),   "vec3",
                          c("A", "B"),             "vec1")
Geet
  • 2,515
  • 2
  • 19
  • 42

5 Answers5

4

A solution using map2_lgl and identical to assess if the vectors are the same.

library(tidyverse)

df_new <- df %>%
  mutate(y = case_when(
    map2_lgl(x, list(vec1), ~identical(.x, .y))  ~"vec1",
    map2_lgl(x, list(vec2), ~identical(.x, .y))  ~"vec2",
    map2_lgl(x, list(vec3), ~identical(.x, .y))  ~"vec3"
  ))
df_new
# # A tibble: 4 x 2
#   x         y    
#   <list>    <chr>
# 1 <chr [2]> vec1 
# 2 <chr [3]> vec2 
# 3 <chr [4]> vec3 
# 4 <chr [2]> vec1 
www
  • 38,575
  • 12
  • 48
  • 84
  • It worked, fantastic!! Do we need "df$" in map2_lgl statements? – Geet Apr 23 '18 at 20:33
  • @Geet We don't need `df$x`, just `x` would work. Thanks for pointing that out. I have updated my answer. – www Apr 23 '18 at 20:37
2

Here's an alternative that's more programmatic - you don't need to specify each vector explicitly

Data

df <- tibble::tribble(~x,
                      c("A", "B"),
                      c("A", "B", "C"),
                      c("A", "B", "C", "D"),
                      c("A", "B"))

vec1 <- c("A", "B")
vec2 <- c("A", "B", "C")
vec3 <- c("A", "B", "C", "D")

Solution - takes advantage of ls(...) to return relevant vector names using a pattern

vecs <- ls(pattern="vec")
L <- lapply(vecs, get)
names(L) <- vecs
df %>%
  mutate(y = names(L)[match(x, L)])

# A tibble: 4 x 2
  # x         y    
  # <list>    <chr>
# 1 <chr [2]> vec1 
# 2 <chr [3]> vec2 
# 3 <chr [4]> vec3 
# 4 <chr [2]> vec1
CPak
  • 13,260
  • 3
  • 30
  • 48
1

This would work too:

comp <- list(vec1, vec2, vec3)

df %>% 
  mutate(y = map_chr(df$x, ~ paste0("vec", which(comp %in% list(.)))))

# A tibble: 4 x 2
  x         y    
  <list>    <chr>
1 <chr [2]> vec1 
2 <chr [3]> vec2 
3 <chr [4]> vec3 
4 <chr [2]> vec1 
erocoar
  • 5,723
  • 3
  • 23
  • 45
1

An option is to use compare::compareEqual with apply as:

library(dplyr)
library(compare)

df$y <- apply(df,1, function(x){
  dplyr::case_when(
    isTRUE(compareEqual(x[[1]], vec1)) ~ "vec1",
    isTRUE(compareEqual(x[[1]], vec2)) ~ "vec2",
    isTRUE(compareEqual(x[[1]],vec3)) ~ "vec3"
  )})



df
# # A tibble: 4 x 2
# x         y    
# <list>    <chr>
# 1 <chr [2]> vec1 
# 2 <chr [3]> vec2 
# 3 <chr [4]> vec3 
# 4 <chr [2]> vec1 
MKR
  • 19,739
  • 4
  • 23
  • 33
  • 1
    I tried replacing compareEqual with the base function all.equal and that worked too. Nice to know about the package compare. – Geet Apr 24 '18 at 18:12
  • @Geet Yea, you can even use `identical`. I wanted to show-case use of `compare` and just simple use of `apply` with `case_when` with my answer, – MKR Apr 24 '18 at 18:20
  • Got it. That was helpful! I learned something new from your code. – Geet Apr 24 '18 at 18:26
1

Unfortunately you can't do a left_join on exotic formats but we can cheat and join on the dput string:

library(tidyverse)
lkp <- enframe(map_chr(lst(vec1,vec2,vec3),~capture.output(dput(.x))))
df %>%
  mutate(value = map_chr(x,~capture.output(dput(.x)))) %>%
  left_join(lkp) %>%
  select(-value)

# # A tibble: 4 x 2
#           x  name
#      <list> <chr>
# 1 <chr [2]>  vec1
# 2 <chr [3]>  vec2
# 3 <chr [4]>  vec3
# 4 <chr [2]>  vec1
moodymudskipper
  • 46,417
  • 11
  • 121
  • 167