Scala内建控制-多重循环

76 阅读3分钟

在 Scala 中,多重循环(嵌套循环)可以通过简洁的语法实现,无需像其他语言那样显式嵌套大括号,而是通过在 for 推导式中用逗号分隔多个迭代变量来表示。这种语法让代码更紧凑,同时支持条件过滤(守卫)和结果收集(yield)。

1. 基础多重循环:嵌套迭代

最常见的场景是遍历多个集合的笛卡尔积,例如双层循环遍历行和列。

示例:打印 3x3 的矩阵索引

// 外层循环:i 从1到3(行)
// 内层循环:j 从1到3(列)
for (i <- 1 to 3; j <- 1 to 3) {
  println(s"($i, $j)")
}

输出:

(1, 1)
(1, 2)
(1, 3)
(2, 1)
(2, 2)
(2, 3)
(3, 1)
(3, 2)
(3, 3)

等价于传统嵌套循环的写法:

for (i <- 1 to 3) {
  for (j <- 1 to 3) {
    println(s"($i, $j)")
  }
}

2. 带条件过滤(守卫)的多重循环

可以在多重循环中加入 if 条件,筛选符合要求的组合,避免不必要的迭代。

示例:打印两数之和为 5 的组合(i 从 1 到 4,j 从 1 到 4)

for (
  i <- 1 to 4;
  j <- 1 to 4;
  if i + j == 5  // 守卫条件:两数之和为5
) {
  println(s"$i + $j = 5")
}

输出:

1 + 4 = 5
2 + 3 = 5
3 + 2 = 5
4 + 1 = 5

3. 多重循环中使用 yield 收集结果

通过 yield 可以将多重循环的结果收集为一个新集合,避免手动创建集合并添加元素。

示例:生成 1-3 中两数乘积大于 3 的所有组合及其乘积

val results = for (
  i <- 1 to 3;
  j <- 1 to 3;
  if i * j > 3  // 筛选乘积大于3的组合
) yield (i, j, i * j)  // 收集 (i, j, 乘积) 元组

println(results)

输出:

Vector((2,2,4), (2,3,6), (3,2,6), (3,3,9))

4. 多重循环的控制:提前终止(break)

Scala 没有内置的 break 关键字,但可以通过 scala.util.control.Breaks 工具类实现循环终止。

示例:找到第一个和为 6 的组合后终止循环

import scala.util.control.Breaks._
breakable {  // 包裹需要中断的代码块
  for (i <- 1 to 5; j <- 1 to 5) {
    println(s"检查 ($i, $j)")
    if (i + j == 6) {
      println(s"找到目标:$i + $j = 6")
      break()  // 终止循环
    }
  }
}

输出:

检查 (1, 1)
检查 (1, 2)
检查 (1, 3)
检查 (1, 4)
检查 (1, 5)
检查 (2, 1)
找到目标:2 + 4 = 6  // 找到后立即终止

5. 实际应用:打印九九乘法表

多重循环的经典案例,外层控制行数,内层控制每行的列数(列数 ≤ 行数)。

for (i <- 1 to 9; j <- 1 to i) {  // j 从1到i,确保每行不超过行数
  print(s"$j×$i=${i*j}\t")  // \t 制表符对齐
  if (j == i) println()  // 每行结束后换行
}

输出:

1×1=1	
1×2=2	2×2=4	
1×3=3	2×3=6	3×3=9	
 ...       ...     ...
1×9=9	2×9=18	 ...	9×9=81	

总结

  • Scala 多重循环通过 for (变量1 <- 集合1; 变量2 <- 集合2; ...) 实现,语法简洁。
  • 支持添加多个 if 守卫条件,灵活筛选迭代结果。
  • 用 yield 可直接收集循环结果为集合(如 VectorList 等)。
  • 如需提前终止循环,需借助 Breaks 工具类的 breakable 和 break 方法。