R: R 控制流:if/for/while 条件判断与循环

最后更新:2026-08-26

上一课我们学了运算符,R 程序能"判断真假"了。但光会判断还不够——程序还要能重复做事(循环)和分支选择(条件)。这一课我们学 R 的"控制流":if/else 条件、for/while 循环、repeat 跳出。

R 的控制流和 Python 不太一样:R 用 {} 包围代码块(不用缩进),并且整个 if/else 是一个表达式。这一课我们要掌握这些差异。

1. 你将学到



2. 一个数据筛选的故事

(1) 痛点:手动分类

小赵是数据分析师,manager让他把 100 个客户的年龄做分层:

如果用 Excel,要写 4 个嵌套 IF 公式;如果用 Python,要写循环和 if-else。但 R 有专门为向量设计的 ifelse()——

(2) R 的解法

R
# 5 个客户的年龄
ages <- c(15, 22, 35, 50, 65)

# 一行代码完成 4 档分类(向量化 ifelse)
labels <- ifelse(ages < 18, "未成年",
          ifelse(ages < 31, "青年",
            ifelse(ages < 51, "中年", "老年")))

cat("客户分类:\n")
print(data.frame(年龄 = ages, 类别 = labels))

3 行代码解决 4 档分类。这就是 R 控制流的"向量化"优势——一句话就是一个判断向量



3. if/else:条件分支

(1) if 基本语法

R
# R 用 { } 包围代码块(Python 用缩进)
if (条件) {
  条件为真时执行
}
R
age <- 18

if (age >= 18) {
  cat("你已经成年了\n")
}
# Output:你已经成年了

(2) if-else:二选一

R
if (条件) {
  条件为真时执行
} else {
  条件为假时执行
}
R
score <- 45

if (score >= 60) {
  cat("及格了!\n")
} else {
  cat("不及格,需要补考\n")
}
# Output:不及格,需要补考

(3) if-else if-else:多分支

R
if (条件1) {
  分支1
} else if (条件2) {
  分支2
} else {
  其他
}
R
score <- 85

if (score >= 90) {
  cat("优秀\n")
} else if (score >= 80) {
  cat("良好\n")
} else if (score >= 60) {
  cat("及格\n")
} else {
  cat("不及格\n")
}
# Output:良好

(4) R vs Python 关键差异

特性 R Python
代码块 {} 大括号 缩进(4 空格)
if 写法 if (x > 0) { ... } if x > 0:
整体表达式 if/else 是一个表达式(可赋值) if/else 是语句(不能赋值)
三元运算 ifelse() 专门函数 x if x > 0 else -x
R
# R 的特殊用法:ifelse 是表达式
result <- if (score >= 60) "及格" else "不及格"
result
# [1] "及格"
⚠️ 注意:R 的 if/else 必须有 else 在同一行(如果整体作为表达式)。如果分两行,R 会报语法错。



4. ifelse():向量化判断

(1) 为什么需要 ifelse()?

普通 if 只能判断单个值,但 R 经常需要判断整个向量。这时用 ifelse()

100%
graph LR
    A["x = 1, 2, 3, 4, 5"] --> B["ifelse x > 3 yes no"]
    B --> C["no no no yes yes"]
    
    style A fill:#cce5ff
    style C fill:#d4edda
R
# 普通 if 会报错(只能接受长度 1)
x <- c(1, 2, 3, 4, 5)
if (x > 3) "大" else "小"   # ❌ 报错:condition has length > 1

# 用 ifelse() 解决
ifelse(x > 3, "大", "小")
# [1] "小" "小" "小" "大" "大"

(2) ifelse() 语法

R
ifelse(条件, 条件为真时的值, 条件为假时的值)

(3) 嵌套 ifelse():多档分类

R
ages <- c(15, 22, 35, 50, 65)

# 4 档分类
labels <- ifelse(ages < 18, "未成年",
          ifelse(ages < 31, "青年",
            ifelse(ages < 51, "中年", "老年")))

print(data.frame(年龄 = ages, 类别 = labels))

输出:

TEXT 📖 仅展示
  年龄  类别
1   15 未成年
2   22   青年
3   35   中年
4   50   中年
5   65   老年
💡 提示ifelse() 嵌套超过 3 层建议用 dplyr::case_when()(第 10 课学),更清晰。



5. for 循环:遍历元素

(1) for 基本语法

R
for (变量 in 向量) {
  每次循环执行的代码
}

(2) 遍历向量

R
# 遍历 1:5
for (i in 1:5) {
  cat("第", i, "次循环\n")
}
# Output:
# 第 1 次循环
# 第 2 次循环
# 第 3 次循环
# 第 4 次循环
# 第 5 次循环

# 遍历字符向量
fruits <- c("苹果", "香蕉", "樱桃")
for (fruit in fruits) {
  cat("我喜欢吃", fruit, "\n")
}

(3) 累计求和(经典例子)

R
# 1+2+3+...+100
total <- 0
for (i in 1:100) {
  total <- total + i
}
total
# [1] 5050

(4) ⚠️ R 的循环性能差

R 的 for 循环比 Python 慢 10-100 倍。R 鼓励用向量化运算代替循环:

R
# 慢(循环)
system.time({
  total <- 0
  for (i in 1:1e6) {
    total <- total + i
  }
})
# 用户  系统  流逝 
# 0.40   0.00   0.40  ← 0.4 秒

# 快(向量化)
system.time({
  total <- sum(1:1e6)
})
# 用户  系统  流逝 
# 0.01   0.00   0.01  ← 0.01 秒(快 40 倍)
⚠️ 注意:R 鼓励"向量化优先"——能用 sum() mean() ifelse() 解决的,不要写循环。



6. while 循环:条件循环

(1) while 语法

R
while (条件) {
  条件为真时重复执行
}

(2) 经典例子:猜数字游戏

R
# 目标数字
target <- 42
guess <- 0
attempts <- 0

while (guess != target) {
  guess <- sample(1:100, 1)  # 随机猜
  attempts <- attempts + 1
  if (attempts > 1000) break  # 超过 1000 次放弃
}
cat("用了", attempts, "次猜中\n")

(3) 与 for 的区别

特性 for while
用途 已知次数的循环 未知次数,条件触发
终止 遍历完向量结束 条件为假结束
适用 遍历数据 等待事件、轮询


7. repeat 与 break:无限循环

(1) repeat 语法

R
repeat {
  代码
  if (条件) break  # 必须有 break,否则死循环
}

(2) 实战:菜单选择

R
choice <- 0
repeat {
  cat("\n=== 主菜单 ===\n")
  cat("1. 查天气\n")
  cat("2. 查股票\n")
  cat("0. 退出\n")
  choice <- as.integer(readline("请选择:"))
  
  if (choice == 0) {
    cat("再见!\n")
    break
  } else if (choice == 1) {
    cat("今天晴,25°C\n")
  } else if (choice == 2) {
    cat("上证 3000 点\n")
  } else {
    cat("无效输入\n")
  }
}
⚠️ 注意repeat 必须配合 break,否则会死循环(程序卡住)。



8. next 和 break:循环控制

关键字 作用 场景
next 跳过本轮,进入下一轮 跳过某些元素
break 跳出整个循环 找到目标立即退出
R
# next:跳过偶数
for (i in 1:10) {
  if (i %% 2 == 0) next
  cat(i, " ")
}
# Output:1 3 5 7 9

cat("\n")

# break:找到第一个 7 就退出
for (i in 1:10) {
  if (i == 7) break
  cat(i, " ")
}
# Output:1 2 3 4 5 6


9. 常见陷阱

(1) 浮点比较陷阱

R
# 看似相等,实际不等
0.1 + 0.2 == 0.3
# [1] FALSE  ← 实际是 0.30000000000000004

# 正确做法:容差比较
abs(0.1 + 0.2 - 0.3) < 1e-9
# [1] TRUE

(2) else 必须换行/同行

R
# ❌ 错误:else 单独成行
if (TRUE) {
  cat("yes")
}
else {
  cat("no")
}
# Error: unexpected 'else' in "else"

# ✅ 正确:else 在 if 块的 } 后面
if (TRUE) {
  cat("yes")
} else {
  cat("no")
}
# Output:yes
💡 提示:把 } else { 写在同一行,避免解析歧义。

(3) if 不会自动打印

R
# R 中 if 不会"自动打印"(不像函数调用)
if (TRUE) "yes"
# 没有输出  ← 不打印

# 解决:用 cat() 或 print() 显式输出
if (TRUE) cat("yes\n")
# Output:yes


10. 完整示例:客户分级管理

下面是一个完整工作流示例,把本课所有控制流串起来。

▶ 示例:客户分级与营销策略

R
# ============================================
# 客户分级与营销策略
# 功能:根据年龄+消费金额给客户分级
# ============================================

# 1. 准备 6 个客户数据
customers <- data.frame(
  name = c("Alice", "Bob", "Charlie", "赵六", "钱七", "孙八"),
  age = c(15, 22, 35, 50, 65, 28),
  spend = c(100, 500, 2000, 5000, 10000, 800)
)

# 2. 用 ifelse() 批量分级(向量化)
customers$tier <- ifelse(customers$spend < 500, "普通",
                  ifelse(customers$spend < 3000, "银卡",
                    ifelse(customers$spend < 8000, "金卡", "钻石")))

# 3. 遍历客户,输出营销策略(for 循环)
cat("=== 客户分级与营销策略 ===\n\n")
for (i in 1:nrow(customers)) {
  name <- customers$name[i]
  age <- customers$age[i]
  spend <- customers$spend[i]
  tier <- customers$tier[i]
  
  # 跳过钻石用户(已最优)
  if (tier == "钻石") {
    cat(name, "(", tier, "):", spend, "元,老客户,重点维护\n")
    next
  }
  
  # 跳出条件(演示 break)
  if (spend > 5000) {
    cat(name, ":高消费客户!进入 VIP 流程\n")
  }
  
  # 按年龄推荐营销
  if (age < 18) {
    cat(name, "(", tier, "):未成年,推荐家长卡\n")
  } else if (age < 30) {
    cat(name, "(", tier, "):青年,推送新品\n")
  } else if (age < 50) {
    cat(name, "(", tier, "):中年,推送家庭套餐\n")
  } else {
    cat(name, "(", tier, "):中老年,推送健康产品\n")
  }
}
▶ 试一试

预期输出(节选):

TEXT 📖 仅展示
=== 客户分级与营销策略 ===

Alice( 普通 ):未成年,推荐家长卡
Bob( 普通 ):青年,推送新品
Charlie( 银卡 ):中年,推送家庭套餐
赵六( 金卡 ):中年,推送家庭套餐
钱七( 钻石 ):10000 元,老客户,重点维护
孙八( 银卡 ):青年,推送新品

❓ 常见问题

Q for 循环太慢怎么办?
A R 鼓励"向量化优先"——能用 sum() mean() ifelse() 解决的,不要写 for。R 循环比 Python 慢 10-100 倍,10 万元素以上慎用。
Q 什么时候用 while 不用 for?
A 未知循环次数用 while(如等待事件、猜数字),已知次数用 for(如遍历向量)。repeat + break 用于"无限循环 + 中途退出"。

📖 小节


📝 作业

  1. 基础题:写一个 R 脚本,用 if/else if/else 实现:根据分数 score 输出等级(90+优秀,80+良好,60+及格,否则不及格)。测试 4 个分数:95, 75, 60, 40,把输出截图保存。

  2. 基础题:用 ifelse() 把向量 c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 分为奇数("odd")和偶数("even"),输出结果。

  3. 基础题:用 for 循环计算 5!(5 的阶乘 = 5×4×3×2×1),把过程和结果截图保存。

  4. 进阶题:写一个猜数字游戏:① 用 sample(1:100, 1) 生成 1-100 随机数作为目标;② 用 while 循环让用户输入(readline);③ 提示"太大"或"太小";④ 猜中后输出"恭喜!用了 N 次"。运行测试。

  5. 挑战题:写一段脚本,对 1-100 的整数做如下处理:① 跳过 3 的倍数(next);② 遇到 50 时跳出(break);③ 把剩下的数累加求和。验证结果(应该是 1+2+4+5+7+8+...+49 = ?)。把代码和输出截图保存。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏