上个月我在 Stack Overflow 上看到一个有趣的问题,其中 OP 想将一系列数据框打印为表格,并尝试了双循环,但没有用:
for (i in c("CP", "BK", "IT", "WP")) { for (j in c("DD", "SI")) { data <- get(paste0(i, "_", j, "_comb1")) print(data) } }
这不起作用的原因有两个:
-
print()
不创建表。您必须明确地(例如,通过knitr::kable()
)或不明确地(例如,通过 R Markdown 中的df_print
选项)创建一个表。 - 表必须打印在顶级表达式中。默认情况下,它们不会在循环内生成。
我在那里发布了一个答案,以根据块选项code
创建顶级表达式来打印数据帧。但是,我认为一定有更深层次的问题,我可能对错误的问题提供了正确的答案。也就是说,如果您必须通过名称get()
一系列对象,并且这些名称共享一个模式(例如,原始问题中的*_*_comb1
),也许这些对象本来就不应该存在!
如果它们存在,则意味着作者必须以如下方式创建它们:
CP_DD_comb1 <- ... BK_DD_comb1 <- ... IT_DD_comb1 <- ... WP_DD_comb1 <- ... CP_SI_comb1 <- ... BK_SI_comb1 <- ... IT_SI_comb1 <- ... WP_SI_comb1 <- ...
...
中的代码还必须有一个模式,如subset(data, X1 == "CP" & X2 == "DD")
,这很可能违反 DRY 原则(不要重复自己)。
当您发现自己创建了一系列名称中带有模式的对象时,我会说您可能做错了。与其创建这些全局对象,不如只创建一个对象——一个包含这些对象的列表。例如,如果您想按cyl
和am
变量对mtcars
数据进行分区,则不应创建像cyl_8_am_0
这样的对象。相反,您创建一个列表:
mtcars_list <- split(mtcars, ~ cyl + am)
然后,如果您想为cyl
和am
的每个组合创建一个表,您只需编写一行代码:
knitr::kable(mtcars_list)
这比首先创建几个全局对象(这会污染全局环境),然后通过get()
检索它们(如果您对它的envir
、 mode
和inherits
参数不够小心,这可能会咬你)要优雅和简单得多,最后一张一张打印出来。
我认为您应该很少需要在日常代码中使用get()
,就像您应该很少需要eval()
一样。如果您不得不求助于get()
,则可能存在更深层次的问题,您可能需要停下来重新思考。