Scala从入门到精通04之集合

1. 集合简介

  • Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable特质
  • 对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包
    不可变集合:scala.collection.immutable
    可变集合: scala.collection.mutable
  • Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而
    不会对原对象进行修改。类似于 java 中的 String 对象
  • 可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象
    在操作集合的时候,不可变用符号,可变用方法

1.1. 不可变集合继承图

在这里插入图片描述

  • Set、Map 是 Java 中也有的集合
  • Seq 是 Java 没有的,我们发现 List 归属到 Seq 了,因此这里的 List 就和 Java 不是同一个概念了
  • 我们前面的 for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range
  • String 也是属于 IndexedSeq
  • 我们发现经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列) 6)大家注意 Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序
  • IndexedSeq 和 LinearSeq 的区别:IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位;LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

7.2. 可变集合继承图

在这里插入图片描述

2. 数组

2.1. 不可变数组

2.1.1. 第一种方式定义数组

定义:val arr1 = new Array[Int] (10)

  • new 是关键字
  • [Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定 Any
  • 10),表示数组的大小,确定后就不可以变化
package com.michael.learn.day04

object TestArray {

  def main(args: Array[String]): Unit = {
    // 1. declare an array
    val arr01 = new Array[Int](4)
    println(arr01.length)  // 4

    // 2. Array assignment
    arr01(3) = 10
    arr01.update(0, 9)

    // 3. through the array
    // 3.1. check the array
    println(arr01.mkString(","))  // 9,0,0,10
    // 3.2. for loop
    for(i <- arr01){print(i+" ")} // 9 0 0 10
    println()
    // 3.3. simplify through
    def printx(ele:Int):Unit = {print(ele+" ")}
    arr01.foreach(printx)  // 9 0 0 10
    println()
    arr01.foreach((x) => print(x + " ")) // 9 0 0 10
    println()

    // 4. add an element (create a new array)
    println(arr01.length)
    val ints:Array[Int] = arr01 :+ 5
    ints.foreach(printx)
  }
}

2.1.2. 第二种方式定义数组

val arr1 = Array(1, 2)

  • 在定义数组时,直接赋初始值
  • 使用 apply 方法创建数组对象
package com.michael.learn.day04

object TestArray02 {

  def main(args: Array[String]): Unit = {
    var array02 = Array(1, 3, "michael")
    println(array02.length)  // 3
    for(i <- array02) print(i + " ") // 1 3 michael 
  }
}

2.2. 可变数组

val arr01 = ArrayBuffer[Any] (3, 2, 5)

  • [Any]存放任意数据类型
  • (3, 2, 5)初始化好的三个元素
  • ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer
package com.michael.learn.day04

import scala.collection.mutable.ArrayBuffer

object TestArrayBuffer {

  def main(args: Array[String]): Unit = {
    // 1. create an array and initial it
    val array03 = ArrayBuffer[Any](1, 2, 3)

    // 2. through the array
    for (i <- array03) print(i + " ") // 1 2 3
    println()

    // 3. add new elements
    // 3.1. append element
    array03.+=(4)
    println(array03.mkString(" "))  // 1 2 3 4
    // 3.2. append elements at the end of the array
    array03.append(5, 6)
    println(array03.mkString(" "))  // 1 2 3 4 5 6
    // 3.3. insert elements at the appointed index
    array03.insert(0, 7, 8, 9)
    println(array03.mkString(" "))  // 7 8 9 1 2 3 4 5 6

    // 4. update element
    array03(1) = 9
    println(array03.mkString(" "))  // 7 9 9 1 2 3 4 5 6
    println(array03.length)  // 9
  }
}

2.3. 可变数组与不可变数组的转换

arr1.toBuffer // 不可变数组转可变数组; arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化
arr2.toArray // 可变数组转不可变数组;arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化

package com.michael.learn.day04

import scala.collection.mutable.ArrayBuffer

object TestArrayBuffer2 {

  def main(args: Array[String]): Unit = {
    // 1. create an Array
    val array04 = ArrayBuffer[Int]()

    // 2. append some elements
    array04.append(1, 2, 3)
    println(array04)  // ArrayBuffer(1, 2, 3)

    // 3. ArrayBuffer ==> Array
    val newArr = array04.toArray
    println(newArr.mkString(","))   // 1,2,3

    // 4. Array ==> ArrayBuffer
    val newArrBuffer = newArr.toBuffer
    println(newArrBuffer)        // ArrayBuffer(1, 2, 3)
    newArrBuffer.append(123)
    println(newArrBuffer)        // ArrayBuffer(1, 2, 3, 123)
  }
}

2.4. 多维数组

val arr = Array.ofDimDouble
说明:二维数组中有三个一维数组,每个一维数组中有四个元素

package com.michael.learn.day04

object TestDimArray {
  def main(args: Array[String]): Unit = {
    // 1. create a 2d array
    val arr = Array.ofDim[Int](3, 4)
    arr(1)(2) = 12
    arr(2)(3) = 23

    // 2. through the array
    for (i <- arr){
      for (j <- i){
        print(j+" ")
      }
      println()
    }
    // 0 0 0 0 
    // 0 0 12 0 
    // 0 0 0 23 
  }
}

3. 列表List

3.1. 不可变List

  • List 默认为不可变集合
  • 创建一个 List(数据有顺序,可重复)
  • 遍历 List
  • List 增加数据
  • 集合间合并:将一个整体拆成一个一个的个体,称为扁平化
  • 取指定数据
  • 空集合 Nil
package com.michael.learn.day04

object TestList {
  def main(args: Array[String]): Unit = {
    // 1. create a new list
    val list:List[Int] = List(1, 2, 3, 4)
    println(list)  // List(1, 2, 3, 4)

    val list10 =  1::2::3::4::Nil
    println(list10)  // List(1, 2, 3, 4)

    // 2. add elements
    val list1 = 5::list
    println(list1)  // List(5, 1, 2, 3, 4)

    val list11 =  7::6::5::list
    println(list11)  // List(7, 6, 5, 1, 2, 3, 4)
    val list2 = list.+:(5)
    println(list2)  // List(5, 1, 2, 3, 4)

    // 3. merge lists
    val list3 = List(8, 9)
    val list4 = list3:::list1
    println(list4)  // List(8, 9, 5, 1, 2, 3, 4)

    // 4. get value from list with appointed index
    println(list(1)) // 2

    // 5. though the list
    list.foreach(print)  // 1234
  }
}

3.2. 可变ListBuffer

  • 创建一个可变集合 ListBuffer
  • 向集合中添加数据
  • 打印集合数据
package com.michael.learn.day04

import scala.collection.mutable.ListBuffer

object TestListBuffer {
  def main(args: Array[String]): Unit = {
    // 1. create a new list
    val listBuffer = ListBuffer(1,2,3,4)

    // 2. add elements
    listBuffer.+=(5)
    listBuffer.append(6, 7)
    listBuffer.insert(7, 8)

    // 3. though the list
    listBuffer.foreach((x) => print(x+" ")) // 1 2 3 4 5 6 7 8
    println()

    // 4. update value based on index
    listBuffer(1) = 12
    listBuffer.update(0, 11)
    println(listBuffer)  // ListBuffer(11, 12, 3, 4, 5, 6, 7, 8)

    // 5. delete element
    listBuffer.-(5)
    println(listBuffer)  // ListBuffer(11, 12, 3, 4, 5, 6, 7, 8)
    listBuffer.-=(12)
    println(listBuffer)  // ListBuffer(11, 3, 4, 5, 6, 7, 8)
    listBuffer.remove(5)
    println(listBuffer)  // ListBuffer(11, 3, 4, 5, 6, 8)
  }
}

4. Set集合

Scala 使用的是不可变集合,如果你想使用可变集合,需要引用scala.collection.mutable.Set 包

4.1. 不可变Set

  • Set 默认是不可变集合,数据无序
  • 数据不可重复
  • 遍历集合
package com.michael.learn.day04

object TestSet {
  def main(args: Array[String]): Unit = {
    // 1. create a set (data is unordered)
    val set = Set(1,2,3,4,5,6)
    println(set) // Set(5, 1, 6, 2, 3, 4)

    // 2. data is unrepeated
    val set1 = Set(1,2,3,4,5,6,3)
    println(set1) // Set(5, 1, 6, 2, 3, 4)

    // 3. though the set
    for(i <- set) print(i + " ") // 5 1 6 2 3 4 
  }
}

4.2. 可变mutable.Set

  • 创建可变集合 mutable.Set
  • 打印集合
  • 集合添加元素
  • 向集合中添加元素,返回一个新的 Set
  • 删除数据
package com.michael.learn.day04

import scala.collection.mutable

object TestmutableSet {
  def main(args: Array[String]): Unit = {
    // 1. create a set
    val set = mutable.Set(1,2,3,4,5,6)
    println(set)  // Set(1, 5, 2, 6, 3, 4)

    // 2. add element
    set += 7
    println(set)  // Set(1, 5, 2, 6, 3, 7, 4)

    // 3. add an element to create a new set
    val ints = set.+(8)
    println(ints)  // Set(1, 5, 2, 6, 3, 7, 4, 8)

    // 4. delete value
    set -= 5
    println(set) // Set(1, 2, 6, 3, 7, 4)

    // 6. though the set
    set.foreach(x => print(x+",")) // 1,2,6,3,7,4,
    println()
    println(set.mkString(","))   // 1,2,6,3,7,4
  }
}

5. Map集合

Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射

5.1. 不可变Map

  • 创建不可变集合 Map
  • 循环打印
  • 访问数据
  • 如果 key 不存在,返回 0
package com.michael.learn.day04

object TestMap {
  def main(args: Array[String]): Unit = {
    // 1. create a map
    val map = Map( "a"->1, "b"->2, "c"->3)
    println(map) // Map(a -> 1, b -> 2, c -> 3)

    // 2. get value
    for(ele <- map.keys) print(ele+"="+map.get(ele).get+" ") // a=1 b=2 c=3
    println()

    // 3. return 0 if the key does not exist
    println(map.get("d").getOrElse(0))  // 0
    println(map.getOrElse("d", 0))      // 0

    // 4. though the map
    map.foreach((kv) => print(kv+" "))  // (a,1) (b,2) (c,3) 
  }
}

5.2. 可变Map

  • 创建可变集合
  • 打印集合
  • 向集合增加数据
  • 删除数据
  • 修改数据
package com.michael.learn.day04

import scala.collection.mutable

object TestMutableMap {
  def main(args: Array[String]): Unit = {
    // 1. create a map
    val map = mutable.Map( "a"->1, "b"->2, "c"->3)

    // 2. add a new element
    map.+=("d"->4)
    println(map)    // Map(b -> 2, d -> 4, a -> 1, c -> 3)

    // 3. put 4 into map and get the original value of key a
    val maybeInt:Option[Int] = map.put("a", 4)
    println(map)                      // Map(b -> 2, d -> 4, a -> 4, c -> 3)
    println(maybeInt.getOrElse(0))    // 1

    // 4. delete value
    map.-=("b", "c")
    println(map)    // Map(d -> 4, a -> 4)

    // 5. update value
    map.update("d", 55)
    println(map)   // Map(d -> 55, a -> 4)

    // 6. though map
    map.foreach((kv) => print(kv + " "))  // (d,55) (a,4)
  }
}

6. 元祖

元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组
注意:元组中最大只能有 22 个元素

package com.michael.learn.day04

object TestTuple {
  def main(args: Array[String]): Unit = {
    // 1. create a tuple
    val tuple:(Int, String, Boolean) = (100, "michael", true)
    println(tuple)   // (100,michael,true)

    // 2. get values from tuple
    // 2.1. by  symbol _
    println(tuple._1) // 100
    // 2.2. by index
    println(tuple.productElement(1)) // michael
    // 2.3. by iterator
    for (ele <- tuple.productIterator){print(ele+" ")} // 100 michael true
    println()

    // 3. Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶
    val map1 = Map("a"->1, "b"->2, "c"->3)
    val map2 = Map(("a",1), ("b",2), ("c",3))
    map1.foreach(tuple=>{print(tuple._1 + "=" + tuple._2 + " ")}) // a=1 b=2 c=3
    println()
    map2.foreach(tuple=>{print(tuple._1 + "=" + tuple._2 + " ")}) // a=1 b=2 c=3
  }
}

7. 集合常用函数

7.1. 基本属性和常用操作

  • 获取集合长度
  • 获取集合大小
  • 循环遍历
  • 迭代器
  • 生成字符串
  • 是否包含
package com.michael.learn.day04

object TestList2 {
  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
    // 1. get the length
    println(list.length)  // 7
    // 2. get the size
    println(list.size)    // 7  same as length
    // 3. though the list by for each
    list.foreach(print)   // 1234567
    println()
    // 4. though the list by iterator
    for(ele <- list.iterator){print(ele)}  // 1234567
    println()
    // 5. to string
    println(list.mkString(","))  // 1,2,3,4,5,6,7
    // 6. if contains
    println(list.contains(9))    // false
  }
}

7.2. 衍生集合

  • 获取集合的头
  • 获取集合的尾(不是头的就是尾)
  • 集合最后一个数据
  • 集合初始数据(不包含最后一个)
  • 反转
  • 取前(后)n 个元素
  • 去掉前(后)n 个元素
  • 并集
  • 交集
  • 差集
  • 拉链
  • 滑窗
package com.michael.learn.day04

object TestList3 {
  def main(args: Array[String]): Unit = {
    val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
    val list2: List[Int] = List(4, 5, 6, 7, 8, 9, 10)

    // 1. get the head
    println(list1.head) // 1
    // 2. get the tail (it's either head or tail)
    println(list1.tail) // List(2, 3, 4, 5, 6, 7)
    // 3. get the last one
    println(list1.last) // 7
    // 4. the initial data (without the last one)
    println(list1.init) // List(1, 2, 3, 4, 5, 6)
    // 5. reverse
    println(list1.reverse) // List(7, 6, 5, 4, 3, 2, 1)
    // 6. get the elements
    println(list1.take(3))  // List(1, 2, 3)
    println(list1.takeRight(3)) // List(5, 6, 7)
    // 7. delete eletements
    println(list1.drop(3))   // List(4, 5, 6, 7)
    println(list1.dropRight(3))  // List(1, 2, 3, 4)
    // 8. union
    println(list1.union(list2)) // List(1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 9, 10)
    // 9. intersect
    println(list1.intersect(list2)) // List(4, 5, 6, 7)
    // 10. diff
    println(list1.diff(list2))  // List(1, 2, 3)
    // 11. zip
    println(list1.zip(list2))  // List((1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,10))

    // 12. slide
    list1.sliding(2, 5).foreach(println)
    // List(1, 2)
    // List(6, 7)
  }
}

7.3. 集合计算简单函数

  • sorted:对一个集合进行自然排序,通过传递隐式的 Ordering
  • sortBy:对一个属性或多个属性进行排序,通过它的类型。
  • sortWith:基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑
package com.michael.learn.day05

object TestList05 {
  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 5, -3, 4, 2, -7, 6)

    // 1. sum
    println(list.sum) // 9
    // 2. product by
    println(list.product) // 5040
    // 3. max
    println(list.max)   // 6
    // 4. min
    println(list.min)   // -7
    // 5. sort
    // 5.1. sort by element size
    println(list.sortBy(x => x))  // List(-7, -3, 1, 2, 4, 5, 6)
    // 5.2. sort by absolutely size
    println(list.sortBy(x => x.abs))  // List(1, 2, -3, 4, 5, 6, -7)
    // 5.3. sort by ascending element size
    println(list.sortWith((x, y) => x < y))  // List(-7, -3, 1, 2, 4, 5, 6)
    // 5.4. sort by descending element size
    println(list.sortWith((x, y) => x > y))  // List(6, 5, 4, 2, 1, -3, -7)
  }
}

7.4. 集合计算高级函数

  • 过滤:遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
  • 转化/映射(map):将集合中的每一个元素映射到某一个函数
  • 扁平化
  • 扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten 操作集合中的每个元素的子元素映射到某个函数并返回新集合
  • 分组(group):按照指定的规则对集合的元素进行分组
  • 简化(归约)
  • 折叠

7.4.1. Basic functions

package com.michael.learn.day05

object TestList6 {
  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
    val nestedList: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9, 10))
    val wordList: List[String] = List("hello world", "hello michael", "hello scala")

    // 1. filter
    println(list.filter(x => x % 2 == 0))  // List(2, 4, 6, 8)
    // 2. map
    println(list.map(_+1)) // List(2, 3, 4, 5, 6, 7, 8, 9, 10)
    // 3. flatten
    println(nestedList.flatten) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    // 4. flatten+map(map first then flatten)
    println(wordList.flatMap(x => x.split(" "))) // List(hello, world, hello, michael, hello, scala)
    // 5. group
    println(list.groupBy(_ % 2)) // Map(1 -> List(1, 3, 5, 7, 9), 0 -> List(2, 4, 6, 8))
  }
}

7.4.1. Reduce

Reduce 简化(归约) :通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果

package com.michael.learn.day05

object TestList07 {
  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4)

    //  将数据两两结合,实现运算规则
    val i:Int = list.reduce(_-_)
    println("i = " + i)   // i = -8 (1-2-3-4=-8)

    //  从源码的角度,reduce 底层调用的其实就是 reduceLeft
    println("i2 = " + list.reduceLeft(_-_))   // i2 = -8
    println("i3 = " + list.reduceRight(_-_))  // i2 = -2 (4-3-2-1=-2)
  }
}

7.4.2. Fold

Fold 折叠:化简的一种特殊情况

package com.michael.learn.day05

object TestList08 {
  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4)

    // fold 方法使用了函数柯里化,存在两个参数列表
    // 第一个参数列表为 : 零值(初始值)
    // 第二个参数列表为: 简化规则
    // fold 底层其实为 foldLeft
    println(list.fold(1)(_-_))       // -9 (1-1-2-3-4) = -9)
    println(list.foldLeft(5)(_-_))   // -5
    println(list.foldRight(10)(_-_)) //  8 (1-(2-((3-(4-10))))=8)
  }
}

7.4.3. 两两合并

package com.michael.learn.day05

import scala.collection.mutable

object TestMap02 {
  def main(args: Array[String]): Unit = {
    // 两个 Map 的数据合并
    val map1 = mutable.Map("a"->1, "b"->2, "c"->3)
    val map2 = mutable.Map("a"->4, "b"->5, "d"->6)

    val map3:mutable.Map[String, Int] =  map2.foldLeft(map1){
      (map, kv) => {
        val k = kv._1
        val v = kv._2

        map(k) = map.getOrElse(k, 0) +v
        map
      }
    }
    println(map3)  // Map(b -> 7, d -> 6, a -> 5, c -> 3)
  }
}

7.4.4. Word Count实战一

单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果

package com.michael.learn.day05

object TestWordCount {
  def main(args: Array[String]): Unit = {
    val stringList = List("Hello Scala Hbase kafka", "Hello Scala Hbase", "Hello Scala", "Hello")

    // 1. convert each string into words
    val wordList:List[String] = stringList.flatMap(_.split(" "))
    println(wordList) // List(Hello, Scala, Hbase, kafka, Hello, Scala, Hbase, Hello, Scala, Hello)

    // 2. group by
    val wordToWordsMap:Map[String, List[String]] = wordList.groupBy(word => word)
    println(wordToWordsMap) // Map(Hello -> List(Hello, Hello, Hello, Hello), Hbase -> List(Hbase, Hbase), kafka -> List(kafka), Scala -> List(Scala, Scala, Scala))

    // 3. count
    val wordToCountMap:Map[String, Int] = wordToWordsMap.map(tuple =>(tuple._1, tuple._2.size))
    println(wordToCountMap) // Map(Hello -> 4, Hbase -> 2, kafka -> 1, Scala -> 3)

    // 4. sort
    val sortList:List[(String, Int)] = wordToCountMap.toList.sortWith{_._2 > _._2}
    println(sortList) // List((Hello,4), (Scala,3), (Hbase,2), (kafka,1))

    // 5. top 3
    println(sortList.take(3)) // List((Hello,4), (Scala,3), (Hbase,2))
  }
}

8. 队列

Scala 也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和 dequeue。

package com.michael.learn.day05

import scala.collection.mutable

object TestQueue {
  def main(args: Array[String]): Unit = {
    val que = new mutable.Queue[String]()
    que.enqueue("a", "b", "c")

    println(que.dequeue()) // a
    println(que.dequeue()) // b
    println(que.dequeue()) // c
  }
}

9. 并行集合

Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算

package com.michael.learn.day05

object TestPar {
  def main(args: Array[String]): Unit = {
    val result1 = (0 to 5).map{case _ => Thread.currentThread.getName}
    val result2 = (0 to 5).par.map{case _ => Thread.currentThread.getName}

    println(result1) // Vector(main, main, main, main, main, main)
    println(result2) // ParVector(scala-execution-context-global-11, scala-execution-context-global-11, scala-execution-context-global-11, scala-execution-context-global-12, scala-execution-context-global-14, scala-execution-context-global-12)
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值