Scala中遍历Seq[Row]至指定条件满足时终止并收集数据
解决Scala遍历Seq[Row]直到特定条件终止并收集元素的问题
嘿,作为Scala新手遇到这种迭代终止的问题很正常,我来帮你梳理清楚并给出可行的解决方案!
先明确你的需求
你需要遍历从DataFrame来的Seq[Row],直到遇到第三列(索引为2,因为Row的索引从0开始)值为0的元素时停止迭代,并且要收集包括该元素在内的所有之前元素的第二列(索引1)字符串,最终得到Array(abc,pqr,stu)。
你之前代码的问题
你的尝试代码有几个明显的问题:
- 索引搞错了:你写了
i.getInt(3),但目标列是第三列,对应的索引应该是2(Row的索引从0开始计数,第一列是0,第二列1,第三列2)。 - 语法错误:
breakable块里的for循环写法不对,变量定义和条件判断的语法混乱,比如var temp = i.getInt(3)===0应该是val temp = i.getInt(2) == 0,而且for循环的逻辑需要用大括号包裹起来。 - 没做元素收集:你的代码只处理了终止逻辑,完全没实现收集第二列字符串的部分。
正确的实现方法
我们可以用Scala标准库的scala.util.control.Breaks来实现中断循环,同时用可变集合来动态收集元素。以下是完整可运行的代码:
import scala.util.control.Breaks.{break, breakable} import org.apache.spark.sql.Row // 模拟你的Seq[Row]数据(和你给出的示例一致) val r: Seq[Row] = Seq( Row("1/1/2020", "abc", 1), Row("1/2/2020", "pqr", 1), Row("1/3/2020", "stu", 0), Row("1/4/2020", "opq", 1), Row("1/6/2020", "lmn", 0) ) // 用可变的ArrayBuffer来收集元素,方便动态添加 val collectedStrings = scala.collection.mutable.ArrayBuffer[String]() breakable { for (row <- r) { // 先把当前元素的第二列字符串加入集合 collectedStrings += row.getString(1) // 判断当前元素的第三列是否为0,是就终止循环 if (row.getInt(2) == 0) { break() } } } // 转换为你需要的Array类型 val finalResult = collectedStrings.toArray // 打印结果:Array(abc, pqr, stu) println(finalResult.mkString("[", ", ", "]"))
代码逐行解释
- 导入依赖:先引入
Breaks工具类(用来中断循环)和Spark的Row类。 - 初始化收集容器:用
ArrayBuffer是因为它支持动态添加元素,比不可变集合更高效,适合这种不知道最终元素数量的场景。 - breakable包裹循环:
breakable是一个特殊的代码块,只有在它里面调用break()才会终止循环,不会影响外部代码。 - 遍历+收集+判断终止:每次循环先收集当前元素的第二列,然后检查第三列是否为0,满足条件就立刻中断循环,停止后续遍历。
- 转换为Array:最后把
ArrayBuffer转成你需要的Array类型,和期望输出一致。
可选:更函数式的写法
如果你想尝试Scala的函数式风格,也可以用foldLeft来实现,不需要用break:
val finalResult = r.foldLeft(Seq.empty[String]) { (acc, row) => val updatedAcc = acc :+ row.getString(1) // 遇到第三列为0的元素时,直接返回当前累积的集合,终止后续处理 if (row.getInt(2) == 0) return updatedAcc updatedAcc }.toArray
这种写法通过累积器逐步收集元素,一旦触发终止条件就直接返回结果,同样能达到你的需求。
内容的提问来源于stack exchange,提问作者Vaishak
相关产品推荐
相关产品推荐

