Найти индексы элемента во вложенном списке?

У меня есть список вроде:

mylist <- list(a = 1, b = list(A = 1, B = 2), c = list(C = 1, D = 3))

есть ли способ (без петель) определить положение элементов, например. если я хочу заменить значения «C» на 5, и не имеет значения, где находится элемент «C», могу ли я сделать что-то вроде:

Aindex <- find_index("A", mylist)
mylist[Aindex] <- 5

Я пробовал grepl, и в текущем примере будет работать следующее:

mylist[grepl("C", mylist)][[1]][["C"]]

но это требует предположения об уровне вложенности.

Причина, по которой я спрашиваю, заключается в том, что у меня есть глубокий список значений параметров и именованный вектор значений замены, и я хочу сделать что-то вроде

 replacements <- c(a = 1, C = 5)
 for(i in names(replacements)){ 
    indx <- find_index(i, mylist)
    mylist[indx] <-  replacements[i]
  }

это адаптация к моему предыдущему вопросу: обновить узел (неизвестной глубины), используя xpath в R?, используя списки R вместо XML


person Abe    schedule 01.02.2013    source источник


Ответы (3)


Один из способов — использовать unlist и relist.

mylist <- list(a = 1, b = list(A = 1, B = 2), c = list(C = 1, D = 3))
tmp <- as.relistable(mylist)
tmp <- unlist(tmp)
tmp[grep("(^|.)C$",names(tmp))] <- 5
tmp <- relist(tmp)

Поскольку имена списков из unlist объединяются с ., вам нужно быть осторожным с grep и тем, как называются ваши параметры. Если ни в одном из имен ваших списков нет ., все должно быть в порядке. В противном случае такие имена, как list(.C = 1), попадут в шаблон и будут заменены.

person Blue Magister    schedule 01.02.2013

Основываясь на этом вопросе, вы можете попробовать это рекурсивно так:

find_and_replace <- function(x, find, replace){
  if(is.list(x)){
    n <- names(x) == find
    x[n] <- replace
    lapply(x, find_and_replace, find=find, replace=replace)
  }else{
    x
  }
}

Тестирование в более глубоком mylist:

mylist <- list(a = 1, b = list(A = 1, B = 2), c = list(C = 1, D = 3, d = list(C=10, D=55)))
find_and_replace(mylist, "C", 5)
$a
[1] 1

$b
$b$A
[1] 1

$b$B
[1] 2


$c
$c$C  ### it worked
[1] 5

$c$D
[1] 3

$c$d
$c$d$C ### it worked
[1] 5

$c$d$D
[1] 55
person Carlos Cinelli    schedule 02.10.2014

Теперь это также можно сделать с помощью rrapply в пакете rrapply (расширенная версия базы rapply). Чтобы вернуть позицию элемента во вложенном списке на основе его имени, мы можем использовать специальные аргументы .xpos и .xname. Например, чтобы найти позицию элемента с именем "C":

library(rrapply)

mylist <- list(a = 1, b = list(A = 1, B = 2), c = list(C = 1, D = 3))

## get position C-node
(Cindex <- rrapply(mylist, condition = function(x, .xname) .xname == "C", f = function(x, .xpos) .xpos, how = "unlist"))
#> c.C1 c.C2 
#>    3    1

Затем мы могли бы обновить его значение во вложенном списке с помощью:

## update value C-node
mylist[[Cindex]] <- 5

Два шага также могут быть объединены непосредственно в вызове rrapply:

rrapply(mylist, condition = function(x, .xname) .xname == "C", f = function(x) 5, how = "replace")
#> $a
#> [1] 1
#> 
#> $b
#> $b$A
#> [1] 1
#> 
#> $b$B
#> [1] 2
#> 
#> 
#> $c
#> $c$C
#> [1] 5
#> 
#> $c$D
#> [1] 3
person Joris C.    schedule 13.06.2020