Scala 数组(保姆级教程)

Scala 数组:初学者也能轻松掌握的数据容器

在编程的世界里,数组就像一个装东西的盒子——它能帮你把多个相同类型的数据整齐地放在一起。如果你用过 Java 或 Python,那对“数组”这个概念一定不陌生。但 Scala 的数组可不只是简单的容器,它融合了函数式编程的思想,让操作数据变得更优雅、更高效。今天我们就来深入聊聊 Scala 数组的那些事,从创建到操作,再到实战应用,一步步带你走进这个强大而灵活的数据结构。


创建数组与初始化

在 Scala 中,数组是可变的Array 类型),这意味着你可以随时修改其中的元素。它和 Java 的 int[] 类似,但语法更简洁,类型推断也更智能。

// 创建一个长度为 5 的整型数组,初始值为 0
val numbers = new Array[Int](5)

// 输出:Array(0, 0, 0, 0, 0)
println(numbers)

💡 注释:new Array[Int](5) 创建了一个长度为 5 的整型数组。Int 是类型,5 是长度。数组初始化时,所有元素默认为 0。

如果你希望直接赋初值,可以这样写:

// 直接初始化数组内容
val fruits = Array("苹果", "香蕉", "橙子", "葡萄")

// 输出:Array(苹果, 香蕉, 橙子, 葡萄)
println(fruits)

💡 注释:Array("苹果", "香蕉", "橙子", "葡萄") 是一种简洁的数组初始化方式。Scala 会自动推断出这是一个 Array[String] 类型的数组。

📌 小贴士:你也可以用 val 声明数组,因为数组本身是可变的,但引用不可变。也就是说,你不能重新赋值整个数组(如 fruits = Array("梨")),但可以修改其中的元素。


数组的访问与修改

数组的访问方式和大多数语言一样,使用下标(索引)从 0 开始。你可以像查字典一样,通过索引快速找到某个元素。

val scores = Array(88, 92, 76, 95, 83)

// 获取第 0 个元素(第一个)
println(scores(0))  // 输出:88

// 获取最后一个元素
println(scores(scores.length - 1))  // 输出:83

// 修改第 2 个元素
scores(2) = 80
println(scores)  // 输出:Array(88, 92, 80, 95, 83)

💡 注释:scores(0) 是访问数组元素的标准语法,不是方法调用,而是“apply”方法的简写。scores.length 返回数组长度。修改元素时,使用 scores(index) = value 的语法。

想象一下,数组就像一个书架,每个格子都贴着编号(索引),你可以随时打开某个格子取出或放回一本书(元素)。


遍历数组的多种方式

在实际开发中,你经常需要对数组中的每一个元素进行处理。Scala 提供了多种优雅的遍历方式。

使用 for 循环

val temperatures = Array(22.5, 25.1, 19.8, 23.4, 26.7)

// 传统 for 循环遍历
for (i <- 0 until temperatures.length) {
  println(s"第 ${i + 1} 天的温度是 ${temperatures(i)}℃")
}

💡 注释:0 until temperatures.length 表示从 0 到长度减 1 的区间,不包含终点。i + 1 是为了让输出更人性化,从“第 1 天”开始。

使用 for 推导式(for-comprehension)

// 用 for 推导式提取所有大于 23 的温度
val hotDays = for (temp <- temperatures if temp > 23) yield temp

// 输出:Array(25.1, 23.4, 26.7)
println(hotDays)

💡 注释:for (temp <- temperatures if temp > 23) yield temp 是 Scala 的函数式风格写法。if 是过滤条件,yield 表示生成新元素。这相当于 Python 的列表推导式。

使用 foreach 方法

// 使用 foreach 遍历并打印
temperatures.foreach { temp =>
  println(s"温度:$temp℃")
}

💡 注释:foreach 是数组的高阶方法,接受一个函数作为参数。{ temp => ... } 是函数字面量,表示对每个元素执行操作。


数组常用操作方法

Scala 数组不仅支持基本操作,还内置了许多实用的方法,让你能轻松完成数据处理任务。

求和、最大值、最小值

val sales = Array(1200, 1500, 980, 2100, 1800)

// 求总和
val total = sales.sum
println(s"总销售额:$total 元")  // 输出:总销售额:8580 元

// 求最大值
val maxSale = sales.max
println(s"最高单日销售额:$maxSale 元")  // 输出:最高单日销售额:2100 元

// 求最小值
val minSale = sales.min
println(s"最低单日销售额:$minSale 元")  // 输出:最低单日销售额:980 元

💡 注释:summaxmin 是数组的内置方法,无需手动循环计算,简洁高效。

排序与反转

val grades = Array(85, 92, 78, 96, 88)

// 升序排序
val sortedGrades = grades.sorted
println(sortedGrades)  // 输出:Array(78, 85, 88, 92, 96)

// 降序排序
val reverseGrades = grades.sorted(Ordering[Int].reverse)
println(reverseGrades)  // 输出:Array(96, 92, 88, 85, 78)

// 反转数组(原地操作)
grades.reverse
println(grades)  // 输出:Array(85, 92, 78, 96, 88) —— 注意:reverse 返回新数组,原数组不变

💡 注释:sorted 返回一个新数组,原数组不变。reverse 也返回新数组。如果想修改原数组,可以使用 ArrayBuffer 或手动赋值。


数组与函数式编程的结合

Scala 的强大之处在于它把函数式编程思想完美地融入了数组操作中。你可以用“函数”来处理数据,而不是写一堆循环。

map:映射操作

val prices = Array(100, 150, 200, 250)

// 将每个价格打 9 折
val discounted = prices.map(_ * 0.9)

// 输出:Array(90.0, 135.0, 180.0, 225.0)
println(discounted)

💡 注释:map 是核心函数,它对数组中每个元素应用一个函数。_ * 0.9 是占位符语法,等价于 x => x * 0.9

filter:过滤操作

val ages = Array(18, 22, 16, 25, 17, 30)

// 筛选出成年(≥18)的人
val adults = ages.filter(_ >= 18)

// 输出:Array(18, 22, 25, 30)
println(adults)

💡 注释:filter 保留满足条件的元素,_ >= 18 是一个匿名函数,表示“是否大于等于 18”。

reduce:归约操作

val numbers = Array(1, 2, 3, 4, 5)

// 计算乘积
val product = numbers.reduce(_ * _)

// 输出:120
println(product)

💡 注释:reduce 将数组从左到右合并,_ * _ 表示“将两个数相乘”。它要求数组至少有一个元素。


实际案例:学生成绩分析系统

我们来做一个小项目:分析一组学生的成绩,找出平均分、最高分和不及格人数。

object ScoreAnalyzer {
  def main(args: Array[String]): Unit = {
    val scores = Array(88, 92, 76, 65, 95, 58, 83, 79, 91, 67)

    // 1. 计算平均分
    val average = scores.sum / scores.length
    println(s"平均分:$average")

    // 2. 找出最高分
    val highest = scores.max
    println(s"最高分:$highest")

    // 3. 统计不及格人数(<60)
    val failedCount = scores.count(_ < 60)
    println(s"不及格人数:$failedCount")

    // 4. 生成等级评定
    val grades = scores.map {
      case score if score >= 90 => "优秀"
      case score if score >= 80 => "良好"
      case score if score >= 70 => "中等"
      case score if score >= 60 => "及格"
      case _ => "不及格"
    }

    println("成绩等级:")
    grades.zipWithIndex.foreach { case (grade, index) =>
      println(s"学生${index + 1}:$grade")
    }
  }
}

💡 注释:zipWithIndex 将数组元素与索引配对,方便输出“学生1、学生2”等。case 语法用于模式匹配,是 Scala 的特色功能。


总结与建议

通过这篇文章,你应该已经对 Scala 数组有了全面的认识。它不只是一个数据容器,更是一个可以表达复杂逻辑的强大工具。从创建、访问、遍历,到函数式操作,Scala 数组为你提供了丰富的编程方式。

记住:

  • 使用 Array[T](n) 创建可变数组;
  • mapfilterreduce 实现函数式编程;
  • foreachfor 循环处理遍历任务;
  • 在实际项目中,优先使用高阶函数,代码更简洁、更易维护。

无论你是刚接触 Scala 的初学者,还是有一定经验的开发者,掌握 Scala 数组都是一条通往高效编程的重要路径。下一次写代码时,不妨试试用 map 替代循环,你会爱上这种写法的优雅。

Scala 数组,不只是数据的容器,更是思维的延伸。