Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find the indices of an element in a nested list?

I have a list like:

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

is there an (loop-free) way to identify the positions of the elements, e.g. if I want to replace a values of "C" with 5, and it does not matter where the element "C" is found, can I do something like:

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

I have tried grepl, and in the current example, the following will work:

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

but this requires an assumption of the nesting level.

The reason that I ask is that I have a deep list of parameter values, and a named vector of replacement values, and I want to do something like

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

this is an adaptation to my previous question, update a node (of unknown depth) using xpath in R?, using R lists instead of XML

like image 736
Abe Avatar asked Feb 01 '13 22:02

Abe


People also ask

How do I access nested list index?

You can access a nested list by negative indexing as well. Negative indexes count backward from the end of the list. So, L[-1] refers to the last item, L[-2] is the second-last, and so on.

How do you find the index of an element in a list of lists?

To find the (row, column) index pair of an element in a list of lists, iterate over the rows and their indices using the enumerate() function and use the row. index(x) method to determine the index of element x in the row .

How do you find the number of elements in a nested list?

Use List comprehension to count elements in list of lists. Iterate over the list of lists using List comprehension. Build a new list of sizes of internal lists. Then pass the list to sum() to get total number of elements in list of lists i.e.


2 Answers

One method is to use unlist and 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)

Because list names from unlist are concatenated with a ., you'll need to be careful with grep and how your parameters are named. If there is not a . in any of your list names, this should be fine. Otherwise, names like list(.C = 1) will fall into the pattern and be replaced.

like image 176
Blue Magister Avatar answered Sep 28 '22 01:09

Blue Magister


Based on this question, you could try it recursively like this:

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
  }
}

Testing in a deeper 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
like image 43
Carlos Cinelli Avatar answered Sep 28 '22 00:09

Carlos Cinelli