0

I want to extract the names of the elements of a list on which I am applying a function within the lapply(). EDIT: perhaps this was not clear so just to clarify it has to be done in lapply().

Here is a reproducible example to clarify.

A <- c("z", "y", "x", "v")
B <- c("q", "j", "k", "r")
C <- c("n", "e", "d", "f")

myList <- list(A = A,B = B, C = C)

names_list <- lapply(myList, function(x) {
  ???(x)
})

output: "A" "B" "C"

I am not sure how this could be done, and I cannot find any information online. The closest I have come to the desired output is by using

get_obj_name from the envnames package but it gives me

$A
[1] "x"

$B
[1] "x"

$C
[1] "x"

Thank you for your help.

  • 3
    `list(A, B, C)` creates a nameless list. If your list had names then `names(myList)` would get the names. – Gregor Thomas Jul 06 '23 at 18:01
  • 2
    Strongly related question: [Can lists be created that name themselves based on input object names?](https://stackoverflow.com/q/16951080/903061) – Gregor Thomas Jul 06 '23 at 18:04
  • 2
    But also, if your context is that you are using `lapply` and you want both the names and the items in the list, you can either `lapply` over the names directly, or use the convenience function `purrr::imap` which gives you access to both. This will only work on named lists like `list(A = A, B = B, C = C)`, not unnamed lists like `list(A, B, C)`. – Gregor Thomas Jul 06 '23 at 18:05
  • As I mentioned in the answer below, The question is difficult for because it needs to be done within Lapply. I will look at the purr::imap which you have suggested. – Olivier Grimard Jul 06 '23 at 18:20
  • 2
    You could consider iterating over the *names* and within the function accessing the list object if you needed it. Something like `lapply(names(myList), \(x) myList[[x]])`. This would give you access to both the names and the elements. This, of course, assumes your list has names, which it does not in your example (as has been pointed out). – LMc Jul 06 '23 at 18:29
  • 1
    As I mention in the comment above, the general pattern with wanting to use names in `lapply` is to `lapply` over the names. This will only work if you have a named list, not a nameless list like `myList` in your question - for a nameless list like in your example I think it is hopeless. But if you have a named list like `named_list <- list(A = A, B = B, C = C)` then you can do `names(named_list)` to get the names and use both the names and items in an `lapply` something like `lapply(names(named_list), \(nm) setNames(nm, named_list[[nm]][1]))` – Gregor Thomas Jul 06 '23 at 18:32
  • 1
    If your real problem is with a named list, then I would encourage you to edit your example `myList` to be a list with names. You could create it with `named_list <- list(A = A, B = B, C = C)`, or you could add the names after creation with `myList <- list(A, B, C); names(myList) = c("A", "B", "C")`, but as long as the example in your question is a nameless list, I don't think there will be any good progress made toward helping get names from it. – Gregor Thomas Jul 06 '23 at 18:35
  • 1
    Also possible duplicate: [Access lapply index names inside FUN](https://stackoverflow.com/q/9950144/903061). – Gregor Thomas Jul 06 '23 at 18:37
  • Thank you for your comments. My problem is with a named list. Thank you as well for pointing out the other answers. I will edit my question to reflect that – Olivier Grimard Jul 06 '23 at 18:43

2 Answers2

2

lapply over the list names rather than over the list itself. Form the list using lst from the tibble package as that will automatically add names to the list.

library(tibble)
L <- lst(A, B, C)  # lst creates list and adds names

res <- lapply(names(L), function(nm) {
  x <- L[[nm]]
  print(nm)
  print(x)
  nm
})

Another approach is to pass both the names and the values:

res2 <- Map(function(nm, x) {
  print(nm)
  print(x)
  nm
}, names(L), L)
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
1

Your lists do not have names with how you programmed it. You'd have to code it like this and then you would not need the lapply

A <- c("z", "y", "x", "v")
B <- c("q", "j", "k", "r")
C <- c("n", "e", "d", "f")

myList <- list(A=A, B=B, C=C)

names_list <- lapply(names(myList), function(x) {print(x)})

names_list
stefan_aus_hannover
  • 1,777
  • 12
  • 13