Question about lists and names() returned

Ok, it's late, and I feel like I'm missing something really fundamental.

Why is this happening?

# example, I'm going to make a list that had three data_frames or tibble

library(dplyr)
library(purrr)

a <- data.frame(
  foo = letters[1:10],
  bar = seq(1:10)
)

b <- data.frame(
  foo = letters[1:5],
  bar = seq(1:5)
)

c <- data.frame(
  foo = character(),
  bar = integer()
)

li <- list(
  A = a, B = b, C = c
)


# So, what I want to do is print the name of list and a short message for those that have data
# yes, I know there are other (better) ways, but this is just me simplifying a much bigger thing I'm actually working with
# I expect to get this:
#  "A has data!"
#  "B has data!"

li %>% keep(~nrow(.) > 0) %>% names() %>% map(~print(paste0(.," has data!")))

Instead I got this:

[1] "A has data!"
[1] "B has data!"
[[1]]
[1] "A has data!"

[[2]]
[1] "B has data!"

So I broke it down a bit

keepThese <- li %>% keep(~nrow(.) > 0)
keepThese
# Yep, that's what I expected

keepThese.names <- keepThese %>% names()
keepThese.names
str(keepThese.names)
# Yep again, what I also expected, a character vector of "A", "B"

#let's try again
keepThese.names %>% map(~print(paste0(.," has data!")))

[1] "A has data!"
[1] "B has data!"
[[1]]
[1] "A has data!"

[[2]]
[1] "B has data!"

Same thing? Why?

You have this result because map returns a list

[[1]]
[1] "A has data!"

[[2]]
[1] "B has data!"

but you used print function, that have a side effect, printing, and returns the value printed. (Try x <- print("OK");x - you'll have 2 OK printed not one). In your example it is

[1] "A has data!"
[1] "B has data!"

So the result is expected. Now, either you just want to print and you need to use walk instead of map. It is the same but specifically for side effect, as it returns the input invisibly.

li %>% keep(~nrow(.) > 0) %>% names() %>% walk(~print(paste0(.," has data!")))

Or you don't need to print and you just use map without print. (for example li %>% keep(~nrow(.) > 0) %>% names() %>% map_chr(~paste0(.," has data!"))

Hope it helps.

5 Likes

HA! It does help, and makes total sense.

I laugh because in the project I'm working on I would have changed my code to use walk once I finished testing the module I'm writing (an wouldn't be using print).

Thank you!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.