Scala学习笔记13: 集合

第十三章 集合

在Scala中, 集合 (Collections) 是一种重要的数据结构, 用于存储和操作一组元素 ;

Scala提供了丰富的集合类库, 包括可变和不可变的集合类型, 以及各种高阶函数和操作符, 方便对集合进行操作和转换 ;

常见的Scala集合类型包括:

  1. 列表 (List) : 有序集合, 元素可重复, 使用 List 关键字定义 ;
  2. 集 (Set) : 无须集合, 元素不重复, 使用 Set 关键字定义 ;
  3. 映射 (Map) : 键值对集合, 键不重复, 值可重复, 使用 Map 关键字定义 ;
  4. 数组 (Array) : 定长可变集合, 使用 Array 关键字定义 ;
  5. 元组 (Tuple) : 不同类型元素的有序集合, 使用 (value1, value2, …) 定义 ;

1- 列表 (List)

在Scala中, 列表 (List) 是一种不可变的有序集合, 允许元素重复 ;

列表是基于链表结构实现的, 每个列表都由一个头部元素和一个指向剩余元素列表的尾部组成 ;

Scala的列表提供了丰富的操作方法, 如 mapfilterfoldLeft 等, 用于对列表进行转换和操作 ;

示例:

    // 1. 创建列表: 可以使用List关键字创建列表
    val numbers = List(1, 2, 3, 4, 5)

    // 2. 访问元素: 可以使用索引访问列表中的元素, 索引从0开始
    val firstElement = numbers(0)
    println(firstElement) // 输出: 1

    // 3. 操作列表: 可以使用map, filter, reduce等方法对列表进行操作
    val doubledNumbers = numbers.map(_ * 2)
    println(doubledNumbers) // 输出: List(2, 4, 6, 8, 10)
    val evenNumbers = numbers.filter(_ % 2 == 0)
    println(evenNumbers) // 输出: List(2, 4)
    val sum = numbers.reduce(_ + _)
    println(sum) // 输出: 15

    // 4. 连接列表: 可以使用 `::` 操作符将元素添加到列表的开头
    val newNumbers = 0 :: numbers
    println(newNumbers) // 输出: List(0, 1, 2, 3, 4, 5)

    // 5. 列表模式匹配: 可以使用模式匹配来处理列表中的元素
    val (head, tail) = numbers match {
      case h :: t => (h, t)
      case _ => (0, Nil)
    }
    println(head) // 输出: 1
    println(tail) // 输出: List(2, 3, 4, 5)

Scala的列表是不可变的, 这意味着列表的内容在创建后不可更改 ;

如果需要可变列表, 可以使用 scala.collection.mutable.ListBuffer .

2- 集 (Set)

在Scala中, 集合 (Set) 是一种不可变的元素集合, 其中元素不重复 ;

Scala的集合库提供了 Set 特质以及不可变和可变的具体实现, 用于存储一组唯一的元素 ;

集合在Scala中通常用于快速查找和去重操作 ;

示例:

    // 1. 创建集合: 可以使用 `Set` 关键字创建集合
    val numberSet = Set(1, 2, 3, 4, 5)

    // 2. 添加元素: 集合是不可变的, 无法直接添加元素, 但可以通过创建新的集合来添加元素
    val newNumberSet = numberSet + 6

    // 3. 操作集合: 可以使用集合的 `map` 方法来对集合中的每个元素进行操作, `insersect` 方法来求交集, `union` 方法来求并集
    val otherSet = Set(3, 4, 5, 6, 7)
    val intersectSet = numberSet.intersect(otherSet)
    val unionSet = numberSet.union(otherSet)
    println(intersectSet) // 输出: Set(5, 3, 4)
    println(unionSet) // 输出: Set(5, 1, 6, 2, 7, 3, 4)

    // 4. 检查元素: 可以使用 `contains` 方法来检查集合中是否包含某个元素
    val containsFive = numberSet.contains(5)
    println(containsFive) // 输出: true

    // 5. 遍历集合: 可以使用 `foreach` 方法来遍历集合中的每个元素
    numberSet.foreach(println)
    // 输出:
    // 5
    // 1
    // 2
    // 3
    // 4

Scala的集合库还提供了丰富的方法和操作符, 用于对集合进行操作和转换 ;

集合在Scala中是非常常用且强大的数据结构, 适应于各种场景 .

3- 映射 (Map)

在Scala中, 映射 (Map) 是一种键值对的集合, 用于存储一组唯一的键和对应的值 ;

Scala的映射是基于哈希表实现的, 可以快速查找和访问键值对 ;

映射在Scala中非常常用, 用于表示各种数据关系和映射关系 ;

示例:

    // 1. 创建映射: 可以使用 `Map` 关键字创建映射
    val personInfo = Map("name" -> "Jim", "age" -> 18)

    // 2. 访问值: 可以通过键访问映射中的值
    val name = personInfo("name")
    val age = personInfo.getOrElse("age", 0)
    println(s"name: $name, age: $age") // name: Jim, age: 18

    // 3. 添加值: 映射不可变, 无法直接添加键值对, 可以通过创建新的映射来添加键值对, 可以使用 `+` 运算符添加键值对
    val newPersonInfo = personInfo + ("gender" -> "male")
    println(newPersonInfo) // Map(name -> Jim, age -> 18, gender -> male)

    // 4. 操作映射: 可以使用各种方法对映射进行操作, 例如: `keys` 获取所有键, `values` 获取所有值, `contains` 判断是否存在键
    val keys = personInfo.keys
    val values = personInfo.values
    println(keys) // Set(name, age)
    println(values) // MapLike(Jim, 18)
    println(personInfo.contains("name")) // true
    println(personInfo.contains("gender")) // false

    // 5. 遍历映射: 可以使用 `foreach` 方法遍历映射, 并执行指定的操作
    personInfo.foreach {
      case (key, value) => println(s"$key: $value")
    }
    /* 输出结果:
    name: Jim
    age: 18
    */

Scala的映射提供了丰富的方法和操作符, 用于对键值对进行操作和转换 ;

映射是一种非常有用的数据结构, 适应于各种场景, 如配置信息, 数据索引等 .

4- 数组 (Array)

在Scala中, 数组 (Array) 是一种可变的有序集合, 用于存储固定大小的元素 ;

Scala的数组与Java的数组类似, 但Scala的数组可以是泛型的, 运行存储不同类型的元素 ;

数组在Scala中是一种基本的数据结构, 常用于需要高性能和可变性的场景 ;

示例:

    // 1. 创建数组: 可以使用 `Array` 关键字创建数组
    val numbers = Array(1, 2, 3, 4, 5)

    // 2. 访问元素: 可以使用索引访问数组中的元素, 索引从0开始
    val firstNumber = numbers(0)
    println(firstNumber) // 输出: 1

    // 3. 更新元素: 由于数组是可变的, 可以使用索引更新数组中的元素
    numbers(0) = 10
    println(numbers(0)) // 输出: 10

    // 4. 操作数组: 可以使用 `map` 方法对数组进行操作, 例如将数组中的每个元素乘以2; `filter` 方法对数组进行过滤, 例如只保留偶数;
    val doubledNumbers = numbers.map(_ * 2)
    println(doubledNumbers.mkString(", ")) // 输出: 20, 4, 6, 8, 10

    val evenNumbers = numbers.filter(_ % 2 == 0)
    println(evenNumbers.mkString(", ")) // 输出: 2, 4

    // 5. 遍历数组: 可以使用 `foreach` 方法遍历数组
    numbers.foreach(println) // 输出: 10 2 3 4 5

    // 6. 转换为列表: 可以使用 `toList` 方法将数组转换为列表
    val numbersList = numbers.toList
    println(numbersList) // 输出: List(10, 2, 3, 4, 5)

Scala的数组提供了高性能和可变性, 适应于需要频繁修改元素的场景 ;

但需要注意的是, 数组是可变的数据结构, 可能引入一些副作用, 因此在函数式编程中建议尽量使用不可变的集合 .

5- 元组 (Tuple)

在Scala中, 元组 (Tuple) 是一种不可变的有序集合, 用于存储固定数量的元素 ;

元组可以包含不同类型的元素, 并且元组的长度是固定的 ;

Scala的元组提供了一种方便的方式来组合和传递多个值, 而不需要创建新的类或结构 ;

示例:

    // 1. 创建元组: 可以使用小括号和逗号创建元组
    val person = ("Tom", 18, "London")

    // 2. 访问元组: 可以使用 `.` 和索引访问元组中的元素, 索引从1开始
    val name = person._1
    val age = person._2
    val city = person._3
    println(name) // 输出: Tom
    println(age) // 输出: 18
    println(city) // 输出: London

    // 3.元组模式匹配: 可以使用模式匹配来解构元组
    person match {
      case (name, age, city) => println(s"$name is $age years old, and lives in $city.")
    }
    // 输出: Tom is 18 years old, and lives in London.

    // 4. 元组转换为列表: 可以使用 `.toList` 方法将元组转换为列表
    val personList = person.productIterator.toList
    println(personList) // 输出: List(Tom, 18, London)

    // 5. 遍历元组: 可以使用 `.foreach` 方法遍历元组中的每个元素
    person.productIterator.foreach(println)
    /* 输出:
    Tom
    18
    London
    */

元组的特性: 元组子啊Scala中常用于返回多个值的函数 、临时组合数据等场景 , 具有简洁和灵活的特性 ;

Scala的元组是一种轻量级的数据结构, 适用于需要临时组合多个值的情况 ;

元组的不可变性和固定长度使其在某些场景下非常有用 .

6- 可变和不可变集合

在Scala中, 集合可以分为可变 (mutable) 和不可变 (immutable) 两种类型 ;

不可变集合是指一旦创建就无法更改的集合, 任何修改操作都会返回一个新的集合, 原集合保持不变 ;

相反, 可变集合允许在原地修改其内容, 即可以直接修改集合而不需要创建新的集合 .

不可变集合在Scala中是更常用的选择, 因为他们具有线程安全性和函数式编程的优点 ;

不可变集合的操作不会改变原始集合, 而返回一个新的不可变集合, 这有助于避免副作用和提高代码的可维护性 .

可变集合则适用于需要频繁修改数据的场景, 因为他们允许直接在原地修改集合内容, 而不是创建新的集合 ;

可变集合在某些情况下可以提供更高的性能, 但也需要更多的注意力来管理状态变化 ;

在Scala中, 不可变集合通常位于 scala.collection.immutable 包中, 而可变集合位于 scala.collection.mutable 包中 ;

开发者可以根据具体需求和场景选择合适的集合类型, 以实现更安全、高效的编程 .

7- 添加或者去除元素

在Scala中, 集合中常用的方法用于添加或去除元素包括 ++::+ ;

  1. + : 对于不可变无顺序的集合, + 方法用于向集合中添加元素并返回一个新的集合, 原集合保持不变 ; 例如: 对于Set集合:

        val set = Set(1, 2, 3, 4, 5)
        val newSet = set + 6
        println(newSet) // Set(5, 1, 6, 2, 3, 4)
    
  2. +: : 对于List集合, +: 方法用于在列表的头部添加元素并返回一个新的列表, 原列表保持不变 ; 例如:

        val list = List(3,4,5)
        val newList = 1 +: list
        println(newList) // List(1, 3, 4, 5)
    
  3. :+ : 对于List集合, :+ 方法用于在列表的尾部添加元素并返回一个新的列表, 原列表保持不变 ; 例如:

        val list = List(3,4,5)
        val newList = list :+ 6
        println(newList) // List(3, 4, 5, 6)
    

    这些操作符都会返回新的集合, 不会修改原有的集合 .

8- 化简、折叠和扫描

在Scala中, 集合的化简 (reduce) 、折叠(fold) 和扫描(scan) 是常用的函数式编程操作, 用于对集合中的元素进行聚合计算 ;

  1. 化简 (reduce) :

    • reduce 函数将集合中的元素两两结合, 递归地将结果与下一个元素结合, 最终返回一个值 ;

    • 示例: 对列表中的元素求和

    •     val list = List(1, 2, 3, 4, 5)
          val sum = list.reduce(_ + _)
          println(sum) // 15
      
  2. 折叠 (fold) :

    • fold 函数接受一个初始值和一个二元操作函数, 从初始值开始, 将集合中的元素依次应用于操作函数, 返回最终结果 ;

    • 示例: 对列表中的元素求和, 初始值为 1000

    •     val list = List(1, 2, 3, 4, 5)
          val sum = list.fold(100)((x, y) => x + y) // list.fold(100)(_ + _)
          println(sum) // 115
      
  3. 扫描 (scan) :

    • scan 函数类似于 fold , 但会返回每一步的中间结果组成的集合 ;

    • 示例: 对列表中的元素进行累加扫描

    •     val list = List(1, 2, 3, 4, 5)
          val scanResult = list.scan(-3)(_ + _)
          println(scanResult) // List(-3, -2, 0, 3, 7, 12)
      
          val scanLeftResult = list.scanLeft(-3)(_ + _) // 从左到右
          println(scanLeftResult) // List(-3, -2, 0, 3, 7, 12)
      
          val scanRightResult = list.scanRight(-3)(_ + _) // 从右到左
          println(scanRightResult) // List(12, 11, 9, 6, 2, -3)
      

9- 拉链操作

在Scala中, 拉链操作 (zip) 是一种常见的集合操作, 用于将两个集合的对应元素进行配对 ;

具体来说, 拉链操作会将两个集合中相同位置的元素组成一个元组, 生成一个新的集合 ;

示例:

    val list1 = List(1, 2, 3, 4, 5)
    val list2 = List("A", "B", "C", "D", "E")
    val list3 = list1 zip list2
    println(list3) // List((1,A), (2,B), (3,C), (4,D), (5,E))

// 如果两个列表元素个数不同, 以最少的进行匹配
    val list1 = List(1, 2, 3, 4)
    val list2 = List("A", "B", "C", "D", "E")
    val list3 = list1 zip list2
    println(list3) // List((1,A), (2,B), (3,C), (4,D)

在上面的示例中, list1list2 分别是两个不同类型的集合, 通过 zip 方法进行拉链操作后, 生成了一个包含元组的新集合 list3 , 其中每个元组包含了两个集合对应位置的元素 ;

拉链操作在处理需要将两个集合的元素一一对应的情况下非常有用, 可以方便地将两个集合进行配对操作 .

10- 迭代器

在Scala中, 可以使用迭代器 (Iterator) 来遍历集合 ;

迭代器提供了一种逐个访问集合元素的方式, 适用于需要逐个处理集合元素的场景 ;

示例: 使用迭代器遍历集合的基本方法

    val list = List(1, 2, 3, 4, 5)
    val it = list.iterator

    while (it.hasNext) {
      println(it.next())
    }
    /* 输出: 
    1
    2
    3
    4
    5
    */
  • 在上面的示例中, 首先创建了一个整数列表 list , 然后通过 iterator 方法获取了该列表的迭代器 it ;
  • 接着使用 while 循环和 hasNext 方法判断是否还有下一个元素, 然后使用 next 方法逐个访问并处理元素 .

除了使用 while 循环外, 还可以使用 foreach 方法来简化迭代器的遍历:

    val list = List(1, 2, 3, 4, 5)
    val it = list.iterator

    it.foreach(println) 
    /*
    1
    2
    3
    4
    5
    */

通过以上方法, 您可以方便地使用迭代器遍历Scala集合中的元素 .

end

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值