0

I have an appearingly very simple task but can't figure out what I'm doing wrong. I have a list of 3 Xx2 tibbles (in the example 2x2) having a character vector and an integer vector. I want to convert it to a list of 3 named vectors where the letters are the vector elements and the numbers are the names. Here is my approach:

tbl <- tibble(numbers=c(1:2), letters=letters[1:2])
vec_names <- c("name1", "name2", "name3")
lst <- list(tbl, tbl, tbl)
names(lst) <- vec_names
lst_n <- lapply(lst, function(x) x[["letters"]]) 
lst_n <- sapply(vec_names, 
    function(x) names(lst_n[[x]]) <- lst[[x]]$numbers)

I get this result

lst_n
     name1 name2 name3
[1,]     1     1     1
[2,]     2     2     2

and I can't see my mistake. Doing

names(lst_n[["name1"]]) <- lst[["name1"]]$numbers

gives me exactly what I want for "name1" but why doesn't it work with sapply?

I had [] before and changed it to [[]] to access the tibbles inside the list instead of the list elements but it still doesn't work. Can anyone help? It seems like a very basic task.

n.o
  • 3
  • 4
  • sapply try to simplify the result by default, if yo're after a list as output, just use lapply. See [this answer for more details on the apply family](https://stackoverflow.com/questions/3505701/grouping-functions-tapply-by-aggregate-and-the-apply-family/7141669#7141669) – Tensibai Oct 02 '18 at 13:10
  • 1
    Possible duplicate of [Grouping functions (tapply, by, aggregate) and the \*apply family](https://stackoverflow.com/questions/3505701/grouping-functions-tapply-by-aggregate-and-the-apply-family) – Tensibai Oct 02 '18 at 13:11
  • `Error in FUN(X[[i]], ...) : object 'lst_techkeys_batmob' not found` – Maurits Evers Oct 02 '18 at 13:11
  • [Please make your example reproducible](https://stackoverflow.com/q/5963269/2204410). That will make it a lot easier for others to help you. – Jaap Oct 02 '18 at 13:35
  • Just a little tip, you don't need an anonymous function for `lapply(lst, function(x) x[["letters"]]) `, it's just `lapply(lst, "[[", "letters")` – Gregor Thomas Oct 02 '18 at 13:48
  • Sorry for the code failure, leftover of my original code. – n.o Oct 02 '18 at 15:58

1 Answers1

0

Here's one way to do it, all in one anonymous function:

z = lapply(lst, function(x) {
  result = x$letters
  names(result) = x$numbers
  return(result)
})

str(z)
# List of 3
#  $ name1: Named chr [1:2] "a" "b"
#   ..- attr(*, "names")= chr [1:2] "1" "2"
#  $ name2: Named chr [1:2] "a" "b"
#   ..- attr(*, "names")= chr [1:2] "1" "2"
#  $ name3: Named chr [1:2] "a" "b"
#   ..- attr(*, "names")= chr [1:2] "1" "2"

Your approach got stuck because after you extracted all the letters, you need to iterate over both the letters and the numbers to set the names, but lapply only lets you iterate over one thing. (And assigning inside the lapply doesn't work well, the only thing that matters is the returned object.)

If you couldn't use the approach above, doing things in one pass through lst, you can use Map instead which iterates over multiple lists. We'll use the setNames function instead of names<-(), which is what is called when you try to do names(x) <-.

Map(
  f = setNames,
  object = lapply(lst, "[[", "letters"),
  nm = lapply(lst, "[[", "numbers")
)
# $`name1`
#   1   2 
# "a" "b" 
# 
# $name2
#   1   2 
# "a" "b" 
# 
# $name3
#   1   2 
# "a" "b" 
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • Awesome, thanks Gregor! I was thinking of your first solution but had wasn't sure if assigning values and numbers in one would work. Also your 2nd solution seems very elegant and something I'll try using more. Thanks again! – n.o Oct 02 '18 at 15:56
  • I'm glad you like the second solution, but I like the first much better. The first way loops through `lst` once, getting all the relevant pieces and sticking them together in the right way for the result. The second solution loops through `lst` once to get the letters, again to get the numbers, and then loops over those to stick them together into the result. – Gregor Thomas Oct 02 '18 at 16:16
  • Agreed. In my case, runtime doesn't really matter since I only plot results and it seems valuable to get acquainted with Map() for other applications. – n.o Oct 04 '18 at 04:42