14

Imagine that I have the following list

> test <- list("a" = 1, "b" = 2)

Each element of the list has a name :

> names(test)

Now, I want to extract that name using lapply() because I want to use it in a new function which will be called using lapply. I just don't know how to extract the name of each element.

I've tried using deparse() and substitute() but the outcome is weird :

> lapply(test, function(x) {deparse(substitute(x))})
$a
[1] "X[[i]]"

$b
[1] "X[[i]]"

Does anyone has a clue ?

Precision :

I want to do something like this : I have a list which is like test :

> test <- list("a" = matrix(1, ncol = 3), "b" = matrix(2, ncol = 3))

I want to apply a function to that list which transform the data inside each element and give a specific name for each column :

make_df <- function(x) {
  output <- data.frame(x)
  names(output) <- c("items", "type", NAME_OF_X)
  return(output)
}
lapply(test, make_df)

The expected output is :

> test
$a
     [,1] [,2] [,3]
[1,]    1    1    1
attr(,"names")
[1] "index" "type"  "a"    

$b
     [,1] [,2] [,3]
[1,]    2    2    2
attr(,"names")
[1] "index" "type"  "b"    

I don't know how I can get the name of the element to give a name to my third column.

PAC
  • 5,178
  • 8
  • 38
  • 62
  • 3
    Try with `lapply(names(test), function(x) test[[x]])` By looping with `names`, you have the option to get the value as well as the key – akrun Jun 24 '15 at 12:17
  • 2
    or `lapply(seq_along(test), function(i) names(test[i]))` – Julien Navarre Jun 24 '15 at 12:20
  • Ok, the second one works but I want something which works with the list, not `seq_along()` – PAC Jun 24 '15 at 12:21
  • 2
    @PAC I showed the way to get the value, but if you only need the key `lapply(names(test), function(x) x)` – akrun Jun 24 '15 at 12:23
  • @akrun Why is my question a duplicate ? – PAC Jun 24 '15 at 12:26
  • 1
    You wanted to get the names of the list elements and the link looks like a duplicate of what you wanted – akrun Jun 24 '15 at 12:28
  • @akrun My question is now more precise – PAC Jun 24 '15 at 12:35
  • For the first list element, you have a single column and for second 3 columns. Can you show the expected output? Or did you meant `ncol=3` in place of `nrow=3`? – akrun Jun 24 '15 at 12:37
  • Ok, I've corrected myself – PAC Jun 24 '15 at 12:42
  • Try `make_df <- function(x){ setNames(as.data.frame(test[[x]]), c('items', 'type', x))}; lapply(names(test), make_df)` – akrun Jun 24 '15 at 12:42
  • Now, I saw the expected output. But your code is changing the `matrix` to `data.frame` and in the expected output, you still have a matrix with attribute as names. I am confused now. – akrun Jun 24 '15 at 12:46
  • For the updated expected output `lapply(names(test), function(x) {x1 <- test[[x]];attr(x1, 'names') <- c('items', 'type',x);x1})` – akrun Jun 24 '15 at 12:48
  • It doesn't make much sense to have a different description and expected output. – akrun Jun 24 '15 at 12:56

3 Answers3

8

Here's a solution using purrr. It seems to run faster than the solution by aaronwolden but slower than akrun's solution (if that's important):

library(purrr)
map2(test, names(test), function(vec, name) {
    names(vec) <- c("index", "type", name)
    return(vec)
})

$a
     [,1] [,2] [,3]
[1,]    1    1    1
attr(,"names")
[1] "index" "type"  "a"    

$b
     [,1] [,2] [,3]
[1,]    2    2    2
attr(,"names")
[1] "index" "type"  "b"    
thie1e
  • 3,588
  • 22
  • 22
7

Assuming you meant for both elements of test to contain a 3-columned matrix, you can use mapply() and provide separately the list and the list's names:

  test <- list("a" = matrix(1, ncol = 3), "b" = matrix(2, ncol = 3))

  make_df <- function(x, y) {
    output <- data.frame(x)
    names(output) <- c("items", "type", y)
    return(output)
  }

  mapply(make_df, x = test, y = names(test), SIMPLIFY = FALSE)

which produces:

## $a
##   items type a
## 1     1    1 1
##
## $b
##   items type b
## 1     2    2 2

Update

To achieve the expected output you describe in your updated question:

test.names <- lapply(names(test), function(x) c("index", "type", x))
Map(setNames, test, test.names)

produces:

## $a
##      [,1] [,2] [,3]
## [1,]    1    1    1
## attr(,"names")
## [1] "a"     "index" "type"  
## 
## $b
##      [,1] [,2] [,3]
## [1,]    2    2    2
## attr(,"names")
## [1] "b"     "index" "type"  
aaronwolen
  • 3,723
  • 1
  • 20
  • 21
3

Based on the expected output showed

  make_attr_names <- function(x){
   x1 <- test[[x]]
   attr(x1, 'names') <- c('items','type', x)
   x1}
lapply(names(test), make_attr_names)  
 #[[1]]
 #    [,1] [,2] [,3]
 #[1,]    1    1    1
 #attr(,"names")
 #[1] "items" "type"  "a"    

 #[[2]]
 #    [,1] [,2] [,3]
 #[1,]    2    2    2
 #attr(,"names")
 #[1] "items" "type"  "b"  

Or based on the description

 make_df <- function(x){
       setNames(as.data.frame(test[[x]]), c('items', 'type', x))}
 lapply(names(test), make_df)
 #[[1]]
 # items type a
 #1     1    1 1

 #[[2]]
 #  items type b
 #1     2    2 2
akrun
  • 874,273
  • 37
  • 540
  • 662