for 循环通过迭代一个给定向量或列表,重复执行某个表达式。for 循环的语法是
这样的:
for (var in vector) {
expr
}
var 遍历 vector 中的各个元素值,expr 被反复迭代执行。如果 vector 中有 n 个
元素,那么上述循环就等价于:
var <- vector[[1]]
expr
var <- vector[[2]]
expr
...
var <- vector[[n]]
expr
例如,我们使用迭代变量 i 来构造一个在 1:3 上迭代的循环,并且每次迭代,都把变
量 i 的取值信息输出到屏幕上:
for (i in 1:3){
cat("The value of i is",i,"\n")
}
## The value of i is 1
## The value of i is 2
## The value of i is 3
迭代可作用于所有类型的向量,而不只是数值向量。例如,我们可以用一个字符向量
替代 1:3 这一整数向量:
for (word in c("hello", "new", "world")) {
cat("The current word is", word, "\n")
}
## The current word is hello
## The current word is new
## The current word is world
也可以用一个列表来替代它:
loop_list <- list(
a = c(1, 2, 3),
b = c("a", "b", "c", "d"))
for (item in loop_list) {
cat("item:\n length:", length(item),
"\n class:", class(item), "\n")
}
## item:
## length: 3
## class: numeric
## item:
## length: 4
## class: character
除此之外,还可以用数据框来替代它:
df <- data.frame(
x = c(1, 2, 3),
y = c("A", "B", "C"),
stringsAsFactors = FALSE)
for (col in df) {
str(col)
}
## num [1:3] 1 2 3
## chr [1:3] "A" "B" "C"
之前我们提到过,数据框是一个列表,每一元素(列)的长度必须相同。因此,上述
循环的运行方式和对一个普通列表执行 for 循环是一致的,都是按列,而不是按行进行迭代。
然而,很多时候,我们想按行迭代一个数据框。这时可以使用 for 循环,在一个整数
序列(1 到数据框的行数)上迭代。
i 每次取一个行数,我们就把这一行从数据框中挑出来,然后对这一特定的行进行相
应的操作。以下代码按行迭代数据框,并使用 str( ) 输出每一行的结构:
for (i in 1:nrow(df)) {
row <- df[i,]
cat("row", i, "\n")
str(row)
cat("\n")
}
## row 1
## 'data.frame': 1 obs. of 2 variables:
## $ x: num 1
## $ y: chr "A"
##
## row 2
## 'data.frame': 1 obs. of 2 variables:
## $ x: num 2
## $ y: chr "B"
##
## row 3
## 'data.frame': 1 obs. of 2 variables:
## $ x: num 3
## $ y: chr "C"
这里要给一个小小的警告。一般来说,按行迭代数据框并不是一个好主意,因为迭代
过程可能很慢很繁琐。更好的方法是使用第 5 章中介绍的 apply 函数族,或者第 12 章中
介绍的更强大、更高级的扩展包。
在前面的例子中,for 循环的每一次迭代都是相互独立的。有时,可以利用循环外的
变量来记录迭代状态或累积过程。最简单的例子是计算从 1~100 的和:
s <- 0
for (i in 1:100){
s <- s + i
}
s
## [1] 5050
上述例子展示了使用 for 循环进行累计求和。接下来的例子中,我们使用随机数生成
器从正态分布中进行抽样,简单地模拟一下随机游走过程(random walk):
set.seed(123)
x <- numeric(1000)
for (t in 1:(length(x) -1)) {
x[[t + 1]] <- x[[t]] + rnorm(1, 0, 0.1)
}
plot(x, type = "s", main = "Random walk", xlab = "t")
以上代码的输出结果,如图 4-1 所示。
图 4-1
上述两个例子中,尽管 for 循环过程的每一步都依赖于上一步的结果,但可以利用现
有函数,如 sum( ) 和 cumsum( ) 简化循环结构:
sum100 <- sum(1:100)
random_walk <- cumsum(rnorm(1000,0,0.1))
这些函数的基本思想和 for 循环类似,但它们是基于 C 语言的向量化实现,所以运
行效率远高于 R 中的 for 循环。因此,在可能的情况下,应该优先考虑使用这些内置函数。
1.管理 for 循环的控制流
有时,有必要对 for 循环进行干预。在每一次迭代中,我们可以选择中断 for 循环,
跳过当前迭代,或者什么都不做并终止循环。
可以使用 break 终止 for 循环:
for (i in 1:5) {
if(i == 3) break
cat("message", i, "\n")
}
## message 1
## message 2
这种方法可以用来寻找某个问题的解。以下代码试图在 1000 至 1100 之间找到满
足 (i ^ 2) %% 11 等于 (i ^ 3)%%17 的数,其中 ^ 是指数运算符,%% 是除法运算中的取
余运算符:
m <- integer()
for (i in 1000:1100) {
if ((i ^ 2) %% 11 == (i ^ 3) %% 17){
m <- c(m, i)
}
}
m
## [1] 1055 1061 1082 1086 1095
如果只要该范围内满足条件的一个数,你可以将记录追踪表达式(m <-c(m,i))替
换成一个简单的 break:
for (i in 1000:1100) {
if ((i ^ 2) %% 11 == (i ^ 3) %% 17) break
}
i
## [1] 1055
一旦找到一个解,for 循环就会终止,并将 i 的最后取值保存在当前环境中,这样就
能得到满足条件的解。
有时,也可能需要跳过 for 循环中的某一次迭代。我们可以使用 next 跳过本次迭代
的剩余部分,直接进入循环的下一次迭代:
for (i in 1:5) {
if (i == 3) next
cat("message ", i, "\n")
}
## message 1
## message 2
## message 4
## message 5
2.创建循环嵌套
for 循环中的表达式可以是任何内容,包括另一个 for 循环。例如,如果我们想要穷
举向量中元素的所有排列,可以写一个嵌套两层的 for 循环来解决这个问题:
x <- c("a", "b", "c")
combx <- character()
for (c1 in x){
for (c2 in x) {
combx <- c(combx, paste(c1, c2, sep = ",", collapse = ""))
}
}
combx
## [1] "a,a" "a,b" "a,c" "b,a" "b,b" "b,c" "c,a" "c,b" "c,c"
如果只要不同元素的排列,可以在 for 循环内部加一个判定条件:
combx2 <- character()
for (c1 in x) {
for (c2 in x) {
if (c1 == c2) next
combx2 <- c(combx2, paste(c1, c2, sep = ",", collapse = ""))
}
}
combx2
## [1] "a,b" "a,c" "b,a" "b,c" "c,a" "c,b"
除此之外,也可以去掉判定条件,把 for 循环内部的表达式替换为以下代码,以得到
完全相同的结果:
if (c1 != c2) {
combx2 <- c(combx2, paste(c1, c2, sep = ",", collapse = ""))
}
上述代码展示了嵌套循环是如何工作的,但它并不是解决这个问题的最佳方法。一些
内置函数就可以生成向量元素的排列或组合。给定一个原子向量和每个组合的元素个数,
函数 combn( ) 返回由相应组合构成的一个矩阵:
combn(c("a", "b", "c"), 2)
## [,1] [,2] [,3]
## [1,] "a" "a" "b"
## [2,] "b" "c" "c"
与之类似,函数 expand.grid( ) 返回由相应排列构成的一个数据框:
expand.grid(n = c(1, 2, 3), x = c("a", "b"))
## n x
## 1 1 a
## 2 2 a
## 3 3 a
## 4 1 b
## 5 2 b
## 6 3 b
尽管 for 循环很强大,但 R 中有很多针对特定任务编写的函数。最好优先考虑使用内
置函数,而不是直接把所有内容放到 for 循环中。在下一章中,我将会介绍能够代替许
多 for 循环的 lapply( ) 函数和其他相关函数,这些函数使代码更易于编写和理解。

使用 for 循环的更多相关文章

  1. 【.net 深呼吸】细说CodeDom(8):分支与循环

    有人会问,为啥 CodeDom 不会生成 switch 语句,为啥没生成 while 语句之类.要注意,CodeDom只关心代码逻辑,而不是语法,语法是给写代码的人用的.如果用.net的“反编译”工具 ...

  2. Recurrent Neural Network系列1--RNN(循环神经网络)概述

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...

  3. Python学习--04条件控制与循环结构

    Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...

  4. 模仿Linux内核kfifo实现的循环缓存

    想实现个循环缓冲区(Circular Buffer),搜了些资料多数是基于循环队列的实现方式.使用一个变量存放缓冲区中的数据长度或者空出来一个空间来判断缓冲区是否满了.偶然间看到分析Linux内核的循 ...

  5. 【JS基础】循环

    for 循环的语法: for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 语句 1 在循环(代码块)开始前执行 语句 2 定义运行循环(代码块)的条件 语句 3 在循环(代码块)已被 ...

  6. 【python之路4】循环语句之while

    1.while 循环语句 #!/usr/bin/env python # -*- coding:utf-8 -*- import time bol = True while bol: print '1 ...

  7. To Java程序员:切勿用普通for循环遍历LinkedList

    ArrayList与LinkedList的普通for循环遍历 对于大部分Java程序员朋友们来说,可能平时使用得最多的List就是ArrayList,对于ArrayList的遍历,一般用如下写法: p ...

  8. JavaScript单线程和浏览器事件循环简述

    JavaScript单线程 在上篇博客<Promise的前世今生和妙用技巧>的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...

  9. .NET基础 一步步 一幕幕[循环、逻辑语句块]

    循环.逻辑语句块   好久不写博客了,断更了好几天了,从上周五到今天,从北京到上海,跨越了1213.0公里,从一个熟悉的城市到陌生的城市,还好本人适应力比较好,还有感谢小伙伴的接风咯,一切都不是事,好 ...

  10. Linux进程管理及while循环

    目录 进程的相关概念 进程查看及管理工具的使用 Linux系统作业控制 调整进程优先级 网络客户端工具 bash之while循环 20.1.进程类型 守护进程 daemon,在系统引导过程中启动的进程 ...

随机推荐

  1. stm32的VCC/VDD/VSS/VEE/VBAT的区别

    先看一下stm32vet6的引脚图吧 电路设计以及PCB制作中,经常碰见电源符号:VCC. VDD.VEE.VSS,他们具有什么样的关系那? 一.解释 VCC:C=circuit 表示电路的意思, 即 ...

  2. 获取鼠标经过位置的X、Y坐标

    利用JavaScript获取鼠标经过位置的X.Y坐标方法. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN& ...

  3. VS2012/2013引用对话框的糟糕设计

    先看两张图: 1. 首次打开引用对话框(Reference Manager),Name显示不全: (图1) 2. 然后双击或拖动splitter,让Name显示全: (图2) 3. 下次再打开引用对话 ...

  4. 分区实践 A PRIMARY KEY must include all columns in the table's partitioning function

    MySQL :: MySQL 8.0 Reference Manual :: 23 Partitioning https://dev.mysql.com/doc/refman/8.0/en/parti ...

  5. Ubuntu proxychains && setProxy及 unsetProxy

    https://www.socks-proxy.net/ (ubuntu proxy )[ lantern -addr 0.0.0.0:8787 proxychains4 printenv http: ...

  6. saml,sso

    saml,sso centos version get:// cat /etc/redhat-release

  7. COURSES---poj1469 hdu1083(最大匹配)

    题目链接:http://poj.org/problem?id=1469   http://acm.hdu.edu.cn/showproblem.php?pid=1083 题意:有n个学生p门课, 每门 ...

  8. day18(JDBC事务&连接池介绍&DBUtils工具介绍&BaseServlet作用)

    day18总结 今日思维导图: 今日内容 事务 连接池 ThreadLocal BaseServlet自定义Servlet父类(只要求会用,不要求会写) DBUtils à commons-dbuti ...

  9. centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课

    centos  MySQL主从配置 ntsysv   chkconfig  setup命令  配置MySQL 主从 子shell  MySQL备份  kill命令  pid文件  discuz!论坛数 ...

  10. glog安装与使用

    window环境下glog的安装 载后解压,利用Visual Studio打开google-glog.sln.生成解决方案 打开sln会有几个项目,libglog是动态库,生成dll,libglog_ ...