Как извлечь значения из глубоко вложенного списка, если некоторые элементы уже находятся на более высоком уровне? - PullRequest
0 голосов
/ 07 ноября 2019

Из глубоко вложенного списка я хочу извлечь значения определенной ячейки. Некоторые из подсписков уже NA находятся на более высоком уровне, так что цикл, который хочет извлечь значение более глубокого уровня, приведет к ошибке.

sapply(1:length(li), function(i) li[[i]][[1]]$b$l[2])
# Error: $ operator is invalid for atomic vectors

Я не уверен, какпропустите NA s в такой структуре, например, это завершится неудачно с той же ошибкой:

sapply(1:length(li), function(i) na.omit(li[[i]][[1]]$b$l[2]))

Наконец, попытка try() дает желаемый результат , но ошибка все еще находится врезультат, и я должен раздражать grep().

r <- sapply(1:length(li), function(i) try(li[[i]][[1]]$b$l[2], TRUE))
r[grep("Error", r)] <- NA
r
# [1] "2"  "22" NA  # <- desired result

Может ли это быть более элегантно решено в base R ? Я также хочу избежать клоунады с if - else с.

Мне нравится следующее, но я не представляю, как его использовать, чтобы опустить NA с а-ля dat[!is.na(dat)]:

rapply(li, function(x) !is.na(x), h="l")

Данные

li <- list(list(list(a=list(k=1:3, l=1:3), b=list(k=1:3, l=1:3))),
           list(list(a=list(k=21:23, l=21:23), b=list(k=21:23, l=21:23))),
           list(list(a=NA, b=NA)))

Ответы [ 2 ]

1 голос
/ 07 ноября 2019

Итак, одним из эффективных способов избежать ошибок является использование tryCatch():

r <- sapply(1:length(li), function(i) tryCatch(li[[i]][[1]]$b$l[2], error = function(e) NA))

. Это гарантирует, что вы всегда получите NA, когда есть любой тип ошибки, котораяочень полезное возвращаемое значение.

1 голос
/ 07 ноября 2019

Используя пакет purrr, вы можете сделать

map_dbl(li, ~pluck(., 1, "b","l", 2, .default=NA))

Функция pluck() всегда будет возвращать значение, даже если путь не существует, и мы можем установить значение по умолчанию NAкогда это произойдет

Вы также можете написать свой собственный помощник в базе R.

base_pluck <- function(x, ...) {
  dots <- list(...)
  for(i in dots) {
    if (is.numeric(i) && i>=1 && i <= length(x)) {
      x <- x[[i]]
    } else if( is.character(i) && hasName(x, i)) {
      x <- x[[i]]  
    } else {
      return(NA)
    }
  }
  x
}

sapply(li, function(x) base_pluck(x, 1, "b" , "l", 2))
...