Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply over nested list names: Sub out character in nested list names

Tags:

list

r

recursion

I have lists of unknown structure (nesting) that always terminate with a named vector. I want to substitute all the periods in the list or atomic vector names for an underscore. There's rapply to apply functios to list elements but how do I apply over the list/atomic vector's names? I am after a base R solution but please share all solutions for others.

MWE

x <- list(
    urban = list(
        cars = c('volvo', 'ford'),
        food.dining = list(
            local.business = c('carls'),
            chain.business = c('dennys', 'panera')
        )
    ),
    rural = list(
        land.use = list(
            farming =list(
                dairy = c('cows'),
                vegie.plan = c('carrots')
            )
        ),
        social.rec = list(
            community.center = c('town.square')
        ),
        people.type = c('good', 'bad', 'in.between')
    ),
    other.locales = c('suburban'),
    missing = list(
        unknown = c(),
        known = c()
    ),
    end = c('wow')
)

Desired Outcome

## $urban
## $urban$cars
## [1] "volvo" "ford" 
## 
## $urban$food_dining
## $urban$food_dining$local_business
## [1] "carls"
## 
## $urban$food_dining$chain_business
## [1] "dennys" "panera"
## 
## 
## 
## $rural
## $rural$land_use
## $rural$land_use$farming
## $rural$land_use$farming$dairy
## [1] "cows"
## 
## $rural$land_use$farming$vegie_plan
## [1] "carrots"
## 
## 
## 
## $rural$social_rec
## $rural$social_rec$community_center
## [1] "town.square"
## 
## 
## $rural$people_type
## [1] "good"       "bad"        "in.between"
## 
## 
## $other_locales
## [1] "suburban"
## 
## $missing
## $missing$unknown
## NULL
## 
## $missing$known
## NULL
## 
## 
## $end
## [1] "wow"
like image 462
Tyler Rinker Avatar asked Jan 20 '18 13:01

Tyler Rinker


People also ask

How do I add two nested lists?

Adding Lists to a Two Dimensional Array We can add an element to a nested list with the append() function. In our example, we create a list and append it to one of our existing lists from above. This should result in this list: [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2], [8, 7, 6]]

Can you nest list inside another list?

A list can contain any sort object, even another list (sublist), which in turn can contain sublists themselves, and so on. This is known as nested list. You can use them to arrange data into hierarchical structures.

How do I select an element from a nested list?

Using index() method First, iterate through the sublist in the nested list, then check if that particular element exists in that sub_list . If it exists, find the index of the sub_list and the index of the element in that sub_list .

What are nested lists?

A list that occurs as an element of another list (which may ofcourse itself be an element of another list etc) is known as nested list.


2 Answers

Here is an idea for a recursive function. It first substitutes the periods in the names with underscores. It then checks if the class of an element is list, and if yes, it applies the function on that element. Otherwise, if the class is character, it substitutes the periods in its elements with underscores. Note that this will not work if there are for example data.frames in the list, that would have to be an extension defined in the function as well. Hope this helps!

Function:

my_func <- function(x)
{
    names(x) <- gsub('\\.','_',names(x) )
    for(i in 1:length(x))
    {
      if(any(class(x[[i]])=='list'))
      {
        x[[i]] <- my_func(x[[i]])
      }
    }
    return(x)
}
y <- my_func(x)

Data:

x <- list(
  urban = list(
    cars = c('volvo', 'ford'),
    food.dining = list(
      local.business = c('carls'),
      chain.business = c('dennys', 'panera')
    )
  ),
  rural = list(
    land.use = list(
      farming =list(
        dairy = c('cows'),
        vegie.plan = c('carrots')
      )
    ),
    social.rec = list(
      community.center = c('town.square')
    ),
    people.type = c('good', 'bad', 'in.between')
  ),
  other.locales = c('suburban'),
  missing = list(
    unknown = c(),
    known = c()
  ),
  end = c('wow')
)

Output:

 str(y)

List of 5
 $ urban        :List of 2
  ..$ cars       : chr [1:2] "volvo" "ford"
  ..$ food_dining:List of 2
  .. ..$ local_business: chr "carls"
  .. ..$ chain_business: chr [1:2] "dennys" "panera"
 $ rural        :List of 3
  ..$ land_use   :List of 1
  .. ..$ farming:List of 2
  .. .. ..$ dairy     : chr "cows"
  .. .. ..$ vegie_plan: chr "carrots"
  ..$ social_rec :List of 1
  .. ..$ community_center: chr "town.square"
  ..$ people_type: chr [1:3] "good" "bad" "in.between"
 $ other_locales: chr "suburban"
 $ missing      :List of 2
  ..$ unknown: NULL
  ..$ known  : NULL
 $ end          : chr "wow"
like image 105
Florian Avatar answered Oct 06 '22 14:10

Florian


For list objects, it will rename the list and recursively call the same function for each of its elements. For character objects, it will just return the character.

library('purrr')

fix_names.list <- function(v) {
  names(v) <- gsub('\\.', '_', names(v))
  map(v, fix_names)
}

fix_names.default <- function(v) v

fix_names <- function(v) UseMethod('fix_names')

fix_names(x) %>% str
 # List of 5
 # $ urban        :List of 2
 #  ..$ cars       : chr [1:2] "volvo" "ford"
 #  ..$ food_dining:List of 2
 #  .. ..$ local_business: chr "carls"
 #  .. ..$ chain_business: chr [1:2] "dennys" "panera"
 # $ rural        :List of 3
 #  ..$ land_use   :List of 1
 #  .. ..$ farming:List of 2
 #  .. .. ..$ dairy     : chr "cows"
 #  .. .. ..$ vegie_plan: chr "carrots"
 #  ..$ social_rec :List of 1
 #  .. ..$ community_center: chr "town.square"
 #  ..$ people_type: chr [1:3] "good" "bad" "in.between"
 # $ other_locales: chr "suburban"
 # $ missing      :List of 2
 #  ..$ unknown: NULL
 #  ..$ known  : NULL
 # $ end          : chr "wow"
like image 22
Paul Avatar answered Oct 06 '22 14:10

Paul