为什么使用分配不好?

时间:2013-07-09 22:30:05

标签: r assign

这篇文章(Lazy evaluation in R – is assign affected?)涵盖了一些共同点,但我不确定它是否回答了我的问题。

当我发现assign家族很久以后,我停止使用apply,虽然这纯粹是因为在这种情况下优雅的原因:

names.foo <- letters
values.foo <- LETTERS
for (i in 1:length(names.foo))
  assign(names.foo[i], paste("This is: ", values.foo[i]))

可以替换为:

foo <- lapply(X=values.foo, FUN=function (k) paste("This is :", k))
names(foo) <- names.foo

这也是这个(http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f)R-faq说这应该避免的原因。

现在,我知道assign通常不赞成。但还有其他原因我不知道吗?我怀疑它可能会与范围或懒惰的评估混乱,但我不确定?演示此类问题的示例代码将非常棒。

3 个答案:

答案 0 :(得分:29)

实际上这两个操作是完全不同的。第一个给你26个不同的对象,而第二个只给你一个。第二个对象在分析中将更容易使用。所以我想我会说你已经证明了assign的主要缺点,那就是必须总是使用get来收集或收集所有现在“松散”的类似命名的单个对象“在全球环境中。试着想象一下如何用这26个单独的对象连续做任何事情。一个简单的lapply(foo, func)就足以满足第二种策略。

常见问题解答引用真的只是说使用赋值然后分配名称更容易,但并不意味着它是“坏”。我碰巧把它读作“功能较少”,因为你实际上并没有返回一个被赋值的值。效果看起来是副作用(在这种情况下,assign策略导致26个单独的副作用)。 assign的使用似乎被来自具有全局变量的语言的人所采用,作为避免采用“真R方式”的方式,即使用数据对象进行函数式编程。他们真的应该学习使用列表,而不是用个别命名的项目乱丢他们的工作区。

可以使用另一种分配范例:

 foo <- setNames(  paste0(letters,1:26),  LETTERS)

这会创建一个命名的原子向量而不是命名列表,但仍然可以使用赋予[的名称来访问向量中的值。

答案 1 :(得分:14)

作为fortune(236)的来源,我想我会添加几个例子(另见fortune(174))。

首先,一个测验。请考虑以下代码:

x <- 1
y <- some.function.that.uses.assign(rnorm(100))

运行上面两行代码后,x的值是多少?

assign函数用于提交“远距离操作”(请参阅​​http://en.wikipedia.org/wiki/Action_at_a_distance_(computer_programming)或google)。这通常是很难找到错误的根源。

我认为assign最大的问题在于它会让人们走上思考的道路,让他们远离更好的选择。一个简单的例子是问题中的2组代码。 lapply解决方案更优雅,应该得到提升,但人们了解assign函数这一事实会引导人们选择循环选项。然后他们决定他们需要对循环中创建的每个对象执行相同的操作(如果使用优雅的解决方案,那将只是另一个简单的lapplysapply)并且采用更复杂的方法涉及getapply的循环以及对paste的丑陋调用。然后那些迷恋assign的人尝试做类似的事情:

curname <- paste('myvector[', i, ']')
assign(curname, i)

这并没有达到预期的效果,这导致要么抱怨R(抱怨我隔壁邻居的房子离我太远,因为我选择长途跋涉在街区附近)甚至更糟糕的是,深入研究使用evalparse将其构造的字符串设置为“工作”(然后导致fortune(106)fortune(181))。

答案 2 :(得分:8)

我想指出assign旨在与environment一起使用。

从这个角度来看,上面示例中的“坏”事情是使用不太合适的数据结构(基础环境而不是listdata.framevector ,...)。

附注:同样适用于environment$$<-运算符也有效,因此在很多情况下,显式assignget不是必要的,没有。