1

I want to use a list as a simple dictionary to change values when the lookup to the list is not null. I'd expected this to work, but it doesn't;

assoc_values <- list("A" = "GROUP1", "C" = "GROUP1", "B" = "GROUP2", "D" = "GROUP3")
some_data_table[!is.null(assoc_values[[lookup_column]]), "mapped_col" := assoc_values[[lookup_column]]]

It fails with error msg Error: recursive indexing failed at level 2. I've tried other approaches like ifelse(!is.null(assoc_values[[lookup_column]]), ...) but always fails.

below there is a reproducible example:

library(data.table)
assoc_values <- list("A" = "GROUP1", "C" = "GROUP1", "B" = "GROUP2", "D" = "GROUP2")
some_data_table <- data.table('col1' = seq(1, 10), 'lookup_column' = c('A', 'A', 'E', 'B', 'D', 'C', 'A', 'F', 'C', 'T'))
some_data_table[!is.null(assoc_values[[lookup_column]]), "mapped_col" := assoc_values[[lookup_column]]]
lsmor
  • 4,698
  • 17
  • 38

2 Answers2

2

You don't really need a list here since a named vector would do.

library(data.table)
assoc_values <- c("A" = "GROUP1", "C" = "GROUP1", "B" = "GROUP2", "D" = "GROUP2")
some_data_table <- data.table(col1 = seq(1, 10), 
                              lookup_column = c('A', 'A', 'E', 'B', 'D',
                                                'C', 'A', 'F', 'C', 'T'))


some_data_table[, new_col := assoc_values[lookup_column]]
some_data_table[is.na(new_col), new_col := lookup_column]

some_data_table

#    col1 lookup_column new_col
# 1:    1             A  GROUP1
# 2:    2             A  GROUP1
# 3:    3             E       E
# 4:    4             B  GROUP2
# 5:    5             D  GROUP2
# 6:    6             C  GROUP1
# 7:    7             A  GROUP1
# 8:    8             F       F
# 9:    9             C  GROUP1
#10:   10             T       T
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • This is exactly what I want, Thanks. I wonder why it works different with list and named vector... – lsmor Feb 04 '21 at 10:54
  • list would return a list output. Unless you explicitly need it I guess you are better off using vector. – Ronak Shah Feb 04 '21 at 10:59
  • yes, actually named vectors works better if `lookup_column` is modified inplace because, list would erase null, but vector wouldn't – lsmor Feb 04 '21 at 11:01
1

The error is to mistake '[' with '[[', see this SO post. The solution is to use assoc_values[lookup_column].

some_data_table[!is.null(assoc_values[lookup_column]), 
                "mapped_col" := assoc_values[lookup_column]]

some_data_table
#    col1 lookup_column mapped_col
# 1:    1             A     GROUP1
# 2:    2             A     GROUP1
# 3:    3             E           
# 4:    4             B     GROUP2
# 5:    5             D     GROUP2
# 6:    6             C     GROUP1
# 7:    7             A     GROUP1
# 8:    8             F           
# 9:    9             C     GROUP1
#10:   10             T           
Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
  • Thanks for the answer, It turns out that a named vector works better if the `lookup_column` is the same as `mapped_col`. For some reason lists erase null values, whereas vectors, don't – lsmor Feb 04 '21 at 10:56
  • @lsmor `assoc_values[some_data_table$lookup_column]` has several `NULL` entries named ``. Can you give an example of what you are saying in this case? (I know that to delete a list member, assign `NULL` to it) – Rui Barradas Feb 04 '21 at 11:20
  • given `assoc_list` and `assoc_vector` the same as in my question but one is a named list and the other is a named vector. Then this: `some_data_table[!is.null(assoc_list[lookup_column]), lookup_column := assoc_list[lookup_column]]` produces a different result than this: `some_data_table[!is.na(assoc_vector[lookup_column]), lookup_column := assoc_vector[lookup_column]]` you can check out that the list version deletes null values, whereas the vector version keeps null as original. – lsmor Feb 04 '21 at 11:26