admin管理员组

文章数量:1391999

Unexpected output of set_names()

  • I'm trying to name a list of tibbles using set_names.
  • I expect the names to be "tbl_df, tbl, data.frame"
  • However, the result is "character".

Any ideas why?

library(tidyverse)

l1 <-  # Small list of short tibbles
diamonds |> 
  group_split(cut) |> 
  map(~ .x |> slice(1:2)) |> 
  head(2)

l1 |> # Trying to name them based on their class, but the result is "character" which is wrong:
  set_names(function(x) class(x) |> paste(collapse = ", "))
#> $character
#> # A tibble: 2 × 10
#>   carat cut   color clarity depth table price     x     y     z
#>   <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#> 1  0.22 Fair  E     VS2      65.1    61   337  3.87  3.78  2.49
#> 2  0.86 Fair  E     SI2      55.1    69  2757  6.45  6.33  3.52
#> 
#> $character
#> # A tibble: 2 × 10
#>   carat cut   color clarity depth table price     x     y     z
#>   <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#> 1  0.23 Good  E     VS1      56.9    65   327  4.05  4.07  2.31
#> 2  0.31 Good  J     SI2      63.3    58   335  4.34  4.35  2.75


# Evidence that each element should be named "tbl_df, tbl, data.frame", not character
l1[[1]] |> 
  class() |> 
  paste(collapse = ", ")
#> [1] "tbl_df, tbl, data.frame"

Created on 2025-03-13 with reprex v2.1.1

Unexpected output of set_names()

  • I'm trying to name a list of tibbles using set_names.
  • I expect the names to be "tbl_df, tbl, data.frame"
  • However, the result is "character".

Any ideas why?

library(tidyverse)

l1 <-  # Small list of short tibbles
diamonds |> 
  group_split(cut) |> 
  map(~ .x |> slice(1:2)) |> 
  head(2)

l1 |> # Trying to name them based on their class, but the result is "character" which is wrong:
  set_names(function(x) class(x) |> paste(collapse = ", "))
#> $character
#> # A tibble: 2 × 10
#>   carat cut   color clarity depth table price     x     y     z
#>   <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#> 1  0.22 Fair  E     VS2      65.1    61   337  3.87  3.78  2.49
#> 2  0.86 Fair  E     SI2      55.1    69  2757  6.45  6.33  3.52
#> 
#> $character
#> # A tibble: 2 × 10
#>   carat cut   color clarity depth table price     x     y     z
#>   <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#> 1  0.23 Good  E     VS1      56.9    65   327  4.05  4.07  2.31
#> 2  0.31 Good  J     SI2      63.3    58   335  4.34  4.35  2.75


# Evidence that each element should be named "tbl_df, tbl, data.frame", not character
l1[[1]] |> 
  class() |> 
  paste(collapse = ", ")
#> [1] "tbl_df, tbl, data.frame"

Created on 2025-03-13 with reprex v2.1.1

Share Improve this question asked Mar 13 at 9:19 Rasmus LarsenRasmus Larsen 6,16910 gold badges51 silver badges80 bronze badges 1
  • 2 The issue is that R is not passing each element of l1 to your function - it's passing the names of the elements. But your list doesn't have names yet -> R is creating temporary names which are of type "character", and that's what's being passed to your function. there might be better ways, but you can try setNames(l1, map_chr(l1, ~paste(class(.x), collapse = ", "))) – Tim G Commented Mar 13 at 9:25
Add a comment  | 

3 Answers 3

Reset to default 2

The issue is that R is not passing each element of l1 to your function - it's passing the names of the elements. But your list doesn't have names yet -> R is creating temporary names which are of type "character", and that's what's being passed to your function. there might be better ways, but you can try

library(tidyverse)
l1 <- diamonds |> group_split(cut) |> map(~ .x |> slice(1:2)) |> head(2)

setNames(l1, map_chr(l1, ~paste(class(.x), collapse = ", ")))

$`tbl_df, tbl, data.frame`
# A tibble: 2 × 10
  carat cut   color clarity depth table price     x     y     z
  <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1  0.22 Fair  E     VS2      65.1    61   337  3.87  3.78  2.49
2  0.86 Fair  E     SI2      55.1    69  2757  6.45  6.33  3.52

$`tbl_df, tbl, data.frame`
# A tibble: 2 × 10
  carat cut   color clarity depth table price     x     y     z
  <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1  0.23 Good  E     VS1      56.9    65   327  4.05  4.07  2.31
2  0.31 Good  J     SI2      63.3    58   335  4.34  4.35  2.75

Use lapply:

l1 |>
  set_names(lapply(l1, \(x) class(x) |> paste(collapse=", ")))

$`tbl_df, tbl, data.frame`
# A tibble: 2 × 10
  carat cut   color clarity depth table price     x     y     z
  <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1  0.22 Fair  E     VS2      65.1    61   337  3.87  3.78  2.49
2  0.86 Fair  E     SI2      55.1    69  2757  6.45  6.33  3.52

$`tbl_df, tbl, data.frame`
# A tibble: 2 × 10
  carat cut   color clarity depth table price     x     y     z
  <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1  0.23 Good  E     VS1      56.9    65   327  4.05  4.07  2.31
2  0.31 Good  J     SI2      63.3    58   335  4.34  4.35  2.75

R vanilla

l = 
  ggplot2::diamonds |>
  split(~cut) |>
  lapply(head, 2) |>
  head(2) 

We do not need paste(, collapse='') as suggested in User Tim G's answer, we have toString().

All classes equal, then

setNames(l, rep(toString(class(l[[1]])), length(l)))
# names(l) = rep(toString(class(l[[1]])), length(l))

Differences, then

setNames(l, sapply(l, \(n) toString(class(n))))
# names(l) = sapply(l, \(n) toString(class(n)))
$`tbl_df, tbl, data.frame`
# A tibble: 2 × 10
  carat cut   color clarity depth table price     x     y     z
  <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1  0.22 Fair  E     VS2      65.1    61   337  3.87  3.78  2.49
2  0.86 Fair  E     SI2      55.1    69  2757  6.45  6.33  3.52

$`tbl_df, tbl, data.frame`
# A tibble: 2 × 10
  carat cut   color clarity depth table price     x     y     z
  <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1  0.23 Good  E     VS1      56.9    65   327  4.05  4.07  2.31
2  0.31 Good  J     SI2      63.3    58   335  4.34  4.35  2.75

Why would one do this?

本文标签: