Search code examples
rlistvectortibble

Syntax for using atomic vectors in tibble list columns


I'm trying to deepen my ability to work with tibbles and one of the things that frequently causes me problems is when I try working with elements within a list column.

More specifically, while this document claims that "Lists can contain anything, so a list column can be made up of atomic vectors, other lists, tibbles, etc.", in my experience the elements within a list column must also be a list.

Here's a MWE


tbl <- crossing(a = c(letters[1:5]), b = list(NA)); 
dim(tbl)
# [1] (5,2)
char_vec <- c("a", "b", "cd")

# `char_vec` is an atomic vector, so I expect this to work, but it doesn't
tbl[[1, "b"]] <- char_vec
# Error in `[[<-`:
# ! Assigned data `char_vec` must be compatible with row subscript `1`.
# ✖ 1 row must be assigned.
# ✖ Assigned data has 3 rows.
# ℹ Row updates require a list value. Do you need `list()` or `as.list()`?
# Caused by error in `vectbl_recycle_rhs_rows()`:
# ! Can't recycle input of size 3 to size 1.
# Run `rlang::last_trace()` to see where the error occurred

# This, however, does work
tbl[[1, "b"]] <- list(char_vec)
tbl[[1, "b"]]
# [[1]]
# [1] "a"  "b"  "cd"

Can I use an atomic vector as an element in a list column and I am just using the wrong syntax or is impossible and, if so, why? I thought a list, and thus a list column, could include any type of valid object.


Solution

  • When I need to assign an element to a list column, I normally use [[ twice:

    tbl[["b"]][[1]] = char_vec
    tbl
    # # A tibble: 5 × 2
    #   a     b        
    #   <chr> <list>   
    # 1 a     <chr [3]>
    # 2 b     <lgl [1]>
    # 3 c     <lgl [1]>
    # 4 d     <lgl [1]>
    # 5 e     <lgl [1]>
    

    Or if I'm assigning multiple elements, I use [[ and [:

    tbl[["b"]][2:3] = list(1:3, letters)
    tbl
    # # A tibble: 5 × 2
    #   a     b         
    #   <chr> <list>    
    # 1 a     <chr [3]> 
    # 2 b     <int [3]> 
    # 3 c     <chr [26]>
    # 4 d     <lgl [1]> 
    # 5 e     <lgl [1]> 
    

    This makes sense to me because tbl[["b"]] is the list. If I had a list x = list(1, 1:3, "a") and I wanted to assign the first element, I'd use x[[1]] = char_vec. This is the same, except I am using tbl[["b"]] in place of x.