Oscar Kjell
Oscar Kjell

Reputation: 1651

Get same column by name using same code for two differently structured lists

I have two differently structured lists. And in a function I want to get a column that has the same name in both lists. Is there a generic way to deal with this?

  list_1_1_1 <- list(list(list(tibble::tibble("a" = c(1, 2), "b"=c(3, 4))), list("a"=c(1, 2))))
  list_1_1_1
  # Call column called b
  list_1_1_1[[1]][[1]][[1]]$b

  
  list_1_1 <- list(list(tibble::tibble("a" = c(1, 2), "b"=c(3, 4))), list("a"=c(1, 2)))
  list_1_1
  # Call column called b
  list_1_1[[1]][[1]]$b

I would like to get column called b, with the same line of code that works in the two different situations/examples, is that possible? Thanks in advance.

Upvotes: 5

Views: 54

Answers (2)

Joris C.
Joris C.

Reputation: 6234

With an external package, we can do this out-of-the-box with rrapply (an extension of base-rapply to recurse through a nested list):

library(rrapply)

rrapply(list_1_1_1, condition = function(x, .xname) .xname == "b", how = "flatten")
#> $b
#> [1] 3 4
rrapply(list_1_1, condition = function(x, .xname) .xname == "b", how = "flatten")
#> $b
#> [1] 3 4

The condition argument decides which list elements (data.frame columns in this case) to return and the .xname argument evaluates to the name of the list element (i.e. the column name) under evaluation.

The advantage with respect to a function that greps elements based on the names constructed by unlist is that we can avoid any unexpected behavior:

foo <- function(l, pattern) {
  u <- unlist(l)
  unname(u[grep(pattern, names(u))])
}

## there are two 'a' columns, which are collapsed after unlisting the list
foo(list_1_1_1, "a")
#> [1] 1 2 1 2
## here the individual columns are still present
rrapply(list_1_1_1, condition = function(x, .xname) .xname == "a", how = "flatten")
#> $a
#> [1] 1 2
#> 
#> $a
#> [1] 1 2

## no 'a1' column is present in the data, but new names are assigned by unlist
foo(list_1_1_1, "a1")
#> [1] 1 1
## here no column is returned as expected
rrapply(list_1_1_1, condition = function(x, .xname) .xname == "a1", how = "flatten")
#> named list()

Upvotes: 0

jay.sf
jay.sf

Reputation: 72974

Maybe something like this.

foo <- function(l, pattern) {
  u <- unlist(l)
  unname(u[grep(pattern, names(u))])
}

foo(list_1_1_1, "b")
# 3 4

foo(list_1_1, "b")
# 3 4

Upvotes: 4

Related Questions