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. 一步步从Spring Framework装配掌握SpringBoot自动装配

    目录 Spring Framework模式注解 Spring Framework@Enable模块装配 Spring Framework条件装配 SpringBoot 自动装配 本章总结 Spring ...

  2. Laravel 5.7 No 'Access-Control-Allow-Origin' header is present on the request resource

    前后端项目跨域访问时会遇到此问题,解决方法如下: 创建一个中间件 php artisan make:middleware EnableCrossRequestMiddleware 该中间件的文件路径为 ...

  3. Gitlab邮箱配置

    一些动作会自动发邮件,比如合并代码等 未验证

  4. python操作redis详解

    https://www.cnblogs.com/koka24/p/5841826.html

  5. DNS的MX记录和CNAME记录(转)

    MX记录就是邮件域名对邮件服务器(域名)的映射.可以映射到多个邮件服务器,发送时会选择一台发送. 拿到新域名后,还要再查找DNS,将域名转不ip 原文:http://my.oschina.net/u/ ...

  6. Python总结篇——知识大全

    python基础 Python开发环境搭建 Python变量和基本数据类型 python基本数据类型之操作 python的语法规范及for和while python编码 python文件操作 pyth ...

  7. XShell已经内置rz 直接从Windows拖文件进去终端

    XShell已经内置rz 直接从Windows拖文件进去终端 http://www.jb51.net/LINUXjishu/163820.html 借助securtCRT,使用linux命令sz可以很 ...

  8. 使用spring boot ,和前端thymeleaf模板进行开发路径问题

    加入引用:<html xmlns:th="http://www.thymeleaf.org">1:引用templates模板下面的文件时,不要用/绝对路径. 2:引用s ...

  9. Cocos2d-JS实现的贪吃蛇

    一.前言 相信贪吃蛇大家都玩儿过,我对贪吃蛇的印象就是在电子词典上,一只像素蛇在屏幕游走,饥渴难耐,看着豆子就要去吃,吃到豆子就会长一节,当蛇的身体越来越长的时候,它才发现这个世界变了,每走一步,都是 ...

  10. python基础之if语句

    python之if语句 通用格式 if <test1>: <do something> elif: <do something> else: <do some ...