Access Lapply Index Names Inside Fun

Access lapply index names inside FUN

Unfortunately, lapply only gives you the elements of the vector you pass it.
The usual work-around is to pass it the names or indices of the vector instead of the vector itself.

But note that you can always pass in extra arguments to the function, so the following works:

x <- list(a=11,b=12,c=13) # Changed to list to address concerns in commments
lapply(seq_along(x), function(y, n, i) { paste(n[[i]], y[[i]]) }, y=x, n=names(x))

Here I use lapply over the indices of x, but also pass in x and the names of x. As you can see, the order of the function arguments can be anything - lapply will pass in the "element" (here the index) to the first argument not specified among the extra ones. In this case, I specify y and n, so there's only i left...

Which produces the following:

[[1]]
[1] "a 11"

[[2]]
[1] "b 12"

[[3]]
[1] "c 13"

UPDATE Simpler example, same result:

lapply(seq_along(x), function(i) paste(names(x)[[i]], x[[i]]))

Here the function uses "global" variable x and extracts the names in each call.

R lapply statement with index

The function mapply works like lapply but allows you to supply multiple vectors or lists.

In your case you can create a second vector, the same length of the list, just counting up:

mapply(myfunction, mylist, seq_along(mylist))

Let's try it:

myfunction<- function(values, index){ 
cat("Adding values (", index, "): ", values[1], "...", values[2], " = ", sum(values), "\n" )
invisible(values[1] + values[2])
}

mylist <- list(c(5, 4), c(3, 2), c(1, 3))

mapply(myfunction, mylist, seq_along(mylist))

Result:

Adding values ( 1 ):  5 ... 4  =  9 
Adding values ( 2 ): 3 ... 2 = 5
Adding values ( 3 ): 1 ... 3 = 4

Advanced user fun

Just for fun, a careful reading of the ?lapply manual page reveals that the following also works:

myfunction<- function(values){
print(sprintf("Adding values: %i",substitute(values)[[3]]))
return(values[1] + values[2])
}

lapply(mylist, myfunction)

Which suggests a general function adaptor could be created to supply index to your original function (or any other), modified to expect a second index argument:

myfunction<- function(values,index){
print(sprintf("Adding values: %i",index))
return(values[1] + values[2])
}

Now the adaptor

lapply_index_adaptor=function(f)function(x,...)f(x,substitute(x)[[3]],...)

and now the lapply call, with the adaptor:

lapply(mylist, lapply_index_adaptor(myfunction))

Access and preserve list names in lapply function

I believe that lapply by default keeps the names attribute of whatever you are iterating over. When you store the names of myList in n, that vector no longer has any "names". So if you add that back in via,

names(n) <- names(myList)

and the use lapply as before, you should get the desired result.

Edit

My brains a bit foggy this morning. Here's another, perhaps more convenient, option:

sapply(n,FUN = ...,simplify = FALSE,USE.NAMES = TRUE)

I was groping about, confused that lapply didn't have a USE.NAMES argument, and then I actually looked at the code for sapply and realized I was being silly, and this was probably a better way to go.

How to access index number within lapply

We can use Map on the sequence of the list and cbind

Map(cbind, a2, new = seq_along(a2))

-output

[[1]]
value new
1 11.4 1

[[2]]
value new
1 12.8 2

[[3]]
value new
1 15.6 3

A similar approach with imap

library(purrr)
library(dplyr)
imap(a2, ~ .x %>%
mutate(new = .y))

Or if we need lapply, loop over the sequence, extract the list element with [[ and transform or cbind

lapply(seq_along(a2), function(i) cbind(a2[[i]], new = i))

-output

[[1]]
value new
1 11.4 1

[[2]]
value new
1 12.8 2

[[3]]
value new
1 15.6 3

R:How to get name of element in lapply function?

I renamed list to listy to remove the clash with the base function. This is a variation on Señor O's answer in essence:

do.call(rbind, Map("[<-", listy, TRUE, "group", names(listy) ) )

# x y group
#A.1 1 3 A
#A.2 2 4 A
#B.1 1 7 B
#B.2 2 8 B

This is also very similar to a previous question and answer here: r function/loop to add column and value to multiple dataframes

The inner Map part gives this result:

Map("[<-", listy, TRUE, "group", names(listy) )

#$A
# x y group
#1 1 3 A
#2 2 4 A
#
#$B
# x y group
#1 1 7 B
#2 2 8 B

...which in long form, for explanation's sake, could be written like:

Map(function(data, nms) {data[TRUE,"group"] <- nms; data;}, listy, names(listy) )

As @flodel suggests, you could also use R's built in transform function for updating dataframes, which may be simpler again:

do.call(rbind, Map(transform, listy, group = names(listy)) )

Access names of list elements in a loop

In the purrr package, there are the functions imap() and iwalk(). They take a list and a function with two arguments and apply the function to every element of the list and its index/name. The difference is, that iwalk silently returns NULL and is executed only for side effects (helpful if you map over cat()) and imap() works similar to lapply() only it uses the functions second argument for the list's names.

library(purrr)
lst <- list(a1 = 5:12, b4 = c(34,12,5), c3 = 23:45)

imap(lst,\(x,y) cat("The name of the current list element is", y, "\n"))
#> The name of the current list element is a1
#> The name of the current list element is b4
#> The name of the current list element is c3
#> $a1
#> NULL
#>
#> $b4
#> NULL
#>
#> $c3
#> NULL

iwalk(lst,\(x,y) cat("The name of the current list element is", y, "\n"))
#> The name of the current list element is a1
#> The name of the current list element is b4
#> The name of the current list element is c3

Created on 2022-01-18 by the reprex package (v2.0.1)

index number of nested lapply

Here are a couple of approaches

Using mapply

mapply(function(y, z) {
lapply(c("x", "y", "z"), function(x) {
print(paste(y, x))
print(z)
})
},
mylist,
seq_along(mylist))

Or only lapply

lapply(seq_along(mylist),   function(y) {
lapply(c("x", "y", "z"), function(x) {
print(paste(mylist[y], x))
})
})


Related Topics



Leave a reply



Submit