set_names()返回character而非tbl_df等类型的原因排查
问题:用
set_names为tibble列表命名时得到错误名称"character"的原因 我尝试用set_names函数给一个tibble列表命名,预期每个列表元素的名称是"tbl_df, tbl, data.frame",但实际返回的名称却是"character"。单独获取单个列表元素的类并拼接能得到预期结果,相关R代码示例如下:
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"
原因分析
你用的purrr::set_names(tidyverse默认加载的是这个版本)的.fn参数,默认是处理列表的现有名称,而非列表元素本身:
- 如果列表原本没有名称,它会把字符型的位置序号(比如"1"、"2")传给你定义的函数;
- 你写的
function(x) class(x)里的x其实是"1"这种字符串,class("1")返回的就是"character",所以最终所有元素的名称都变成了"character"。
而你单独测试时,是直接把列表里的tibble元素传给class(),自然能得到正确的类名组合。
解决方法
要实现按每个元素的类来命名,有两种简单方式:
方法1:先生成名称向量再传入set_names
l1 |> set_names(map_chr(l1, ~ class(.x) |> paste(collapse = ", ")))
方法2:直接给列表的names属性赋值
names(l1) <- map_chr(l1, ~ class(.x) |> paste(collapse = ", "))
内容的提问来源于stack exchange,提问作者Rasmus Larsen
相关产品推荐
相关产品推荐

