前言

昨天看到曾老师的推文里面有人循环里无法打印结果到绘图板,问题描述:

004.02 “可恶”的R 循环 - 图1

004.02 “可恶”的R 循环 - 图2

这个问题,简单吗?简单。我会吗?我不会。qaq

至少当时思考了一会儿。

解决方法

这里先写解决的办法,非常简单:

004.02 “可恶”的R 循环 - 图3

啊这。。。

004.02 “可恶”的R 循环 - 图4

真的是“五分钟一百块”啊。

问题背后的知识点

问题解答

下面的代码建立在你理解R 循环语法的基础之上~

先看一个简单的循环:

  1. > for (i in 1:5){
  2. + i
  3. + }
  4. # output
  5. >

果不其然,输出值是空的。这其实也就是上面的图是空的原因:

因为通过绘图函数会直接返回一个结果对象,而这个结果对象就类似于我们上面的i,我们希望直接通过输入对象名的方式来获取对象的返回值,然而它并没返回任何的结果。

这也就是为什么我们通过1)tiff 声明了一个空的图形文件,接着希望2)使用该对象直接获得其返回值保存在文件中(然而它的返回值是空的),接着3)关闭画板,保存到文件。

因为根本就没有返回值,也就是说,上面的二步骤是空的,相当于我们创建了一个图形文件,接着保存了个寂寞~QAQ

可是,为什么呢?

  1. > a = 100
  2. > a
  3. [1] 100
  4. > print(a)
  5. [1] 100

不是可以直接通过变量名直接获得其对象值的返回结果吗?

深入思考

翻开R 语言入门与实战的第160页,有如下描述:

R 语言的for 循环有一个缺点:它不会返回输出结果。

这也就是为什么,我们在循环内部直接使用变量,它没有任何的返回结果;而在外部,可以直接通过变量获取对象值。

那我们就需要使用函数print,通过函数print 来将结果打印到屏幕:

  1. > for (i in 1:5) print(i)
  2. [1] 1
  3. [1] 2
  4. [1] 3
  5. [1] 4
  6. [1] 5

这也就是为什么,上面的问题就这样被解决了:

004.02 “可恶”的R 循环 - 图5

吐槽 R语言

关于print打印

如果你使用过python,肯定不会遇到这样的问题:

  1. for i in range(1,5):
  2. i
  3. # output
  4. i = 5
  5. i
  6. # output

因为默认下,python 必须得使用print 才能将变量打印出来:

  1. for i in range(1,5):
  2. print(i, end = '')
  3. # output
  4. 1234[Finished in 0.1s]
  5. i = 5
  6. print(i)
  7. # output
  8. 5

像我第一次使用R 感动坏了,再也不用使用print 函数了,没想到啊,没想到,你在循环内部还留了一手:

004.02 “可恶”的R 循环 - 图6

不知道是为了什么,外部简化了打印,可以循环内部还是保留了这个所谓的“缺点”。

其他的循环

发现while 循环和repeat 也是如此:

  1. > a = 1
  2. > while (a < 5){
  3. + a
  4. + a = a + 1
  5. + }
  6. #output
  7. > repeat{
  8. + a
  9. + if(a >= 5){
  10. + break}
  11. + a = a + 1
  12. + }
  13. #output

不print 的话,也都没有结果:

  1. > while (a < 5){
  2. + print(a)
  3. + a = a + 1
  4. + }
  5. # output
  6. [1] 1
  7. [1] 2
  8. [1] 3
  9. [1] 4
  10. > a = 1
  11. > repeat{
  12. + a
  13. + if(a >= 5){
  14. + break}
  15. + a = a + 1
  16. + }
  17. > a = 1
  18. > repeat{
  19. + print(a)
  20. + if(a >= 5){
  21. + break}
  22. + a = a + 1
  23. + }
  24. # output
  25. [1] 1
  26. [1] 2
  27. [1] 3
  28. [1] 4
  29. [1] 5

环境冲突

再翻开R 语言入门与实战的第160页,有如下描述:

如果你的循环使用了该环境中已经存在的对象名称,就会发生冲突。

这是因为,R 会将循环遍历某个对象的最后一个结果的值返回给这个用来遍历该对象的变量:

  1. > rm(i)
  2. > i
  3. # 环境只已经删除i
  4. 错误: 找不到对象'i'
  5. > for (i in 1:5) {}
  6. > i
  7. [1] 5

有没有发现,即便你并没有在函数内部使用什么操作,它还是对i 进行了赋值。

而这个循环中声明创建的变量,是会在全局发生作用的,如果你在循环外部曾经用同样的变量名进行过其他赋值,它会覆盖当前环境中已经存在的对象:

  1. > i = 666
  2. > for (i in 1:5) {}
  3. > i
  4. [1] 5

我开始也以为循环和函数一样,创建的是局部变量,原来循环内部也是属于全局的,因此会将变量重新赋值,也就是赋值给遍历对象的最后遍历的结果。

函数就不会发生这种事情,因为变量是在局部被声明的:

  1. > c = function() a = 1
  2. > b = c()
  3. > a
  4. 错误: 找不到对象'a'
  5. > b
  6. [1] 1

小结

使用R 循环一定要小心,我们来复习一下:
1)在使用循环时,如果想要打印对象的返回值,一定需要使用print;

2)在使用循环时,一定要选择不同的变量名,无论是进行遍历时使用的变量还是循环内部重新进行赋值的变量。

004.02 “可恶”的R 循环 - 图7