← 返回首页
scala集合框架
发表时间:2023-09-07 07:46:46
scala集合框架

scala的集合框架

1.集合体系

我们看一下整个集合体系结构,这个结构与Java的集合体系非常相似。

集合的顶层接口是Iterable,Iterable接口下面还有一些子接口,Set、Seq、Map 这几个子接口下面有具体的实现类

set下面有HashSet、LinkedHashSet、SortedSet等等 seq下面有List、Buffer、Range等等 Map下面有HashMap、SortedMap、LinkedHashMap等等 其中Buffer下面还有两个常用的,ArrayBuffer、ListBuffer

这是集合中一些常见的实现类,后面还会关联讲到Array和Tuple这两个数据结构。

2.集合

Scala中的集合是分成可变和不可变两类集合类型,其中可变集合就是说,集合的元素可以动态修改,而不可变集合就是说,集合的元素在初始化之后,就无法修改了。

我们在创建集合的时候,如果不指定具体的包名,默认会使用不可变集合。

3.Set

1).Set 先来看一下Set,Set代表一个没有重复元素的集合,这个集合的特性和Java中Set集合的特性基本一样。Set集合分为可变的和不可变的集合,默认情况下使用的是不可变集合。

Set可以直接使用,并且不需要使用new关键字,因为这个Set不仅仅是一个接口,它还是一个Object。

来看下面代码:

scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

注意:默认情况下直接创建的set集合是一个不可变集合,在这可以看到是在immutable包里面的,不可变集合中的元素一经初始化,就不能改变了,所以初始化后再向里面添加元素就报错了。

scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> s += 4
<console>:9: error: value += is not a member of scala.collection.immutable.Set[Int]
              s += 4
                ^

但是我们发现使用s + 4 这种操作是可以的,这是因为 s + 4 返回的是一个新的集合了,相当于在之前的集合的基础上,创建一个新的集合,新的集合包含之前集合的元素和我们新增的4这个元素。

scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> s + 4
res33: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

如果想要创建一个可变的set集合,可以使用mutable包下面的set集合,显式指定包名。

scala> val s = scala.collection.mutable.Set(1,2,3)
s: scala.collection.mutable.Set[Int] = Set(1, 2, 3)

scala> s += 4
res34: s.type = Set(1, 2, 3, 4)

注意:如果要创建一个空的scala.collection.mutable.Set,必须要指定类型,有点类似Java的泛型。

scala> val s = scala.collection.mutable.Set[Int]()
s: scala.collection.mutable.Set[Int] = Set()

scala> s +=1
res0: s.type = Set(1)

scala> s +=2
res1: s.type = Set(1, 2)

Set常用子类有:HashSet、LinkedHashSet、SortedSet,其特性和Java几乎完全一样。

2).HashSet

HashSet集合分为可变和不可变之分,immutable包下面的是不可变的,后期无法新增元素 在这里可以使用new关键字,也可以不使用,因为HashSet既是class,又是object,但是包名需要指定,否则无法识别。

scala> val s = new scala.collection.mutable.HashSet[Int]()
s: scala.collection.mutable.HashSet[Int] = Set()

scala> s +=1
res35: s.type = Set(1)

scala> s +=2
res36: s.type = Set(1, 2)

scala> s +=5
res38: s.type = Set(1, 5, 2)

如果在创建集合的时候就初始化了元素,则可以省略泛型的定义,集合会自动识别元素的类型。

3).LinkedHashSet

LinkedHashSet只有可变的,没有不可变的。

scala> val s = new scala.collection.mutable.LinkedHashSet[Int]()
s: scala.collection.mutable.LinkedHashSet[Int] = Set()

scala> s +=1
res42: s.type = Set(1)

scala> s +=2
res43: s.type = Set(1, 2)

scala> s +=5
res44: s.type = Set(1, 2, 5)

4).SortedSet

SortedSet分为可变集合和不可变集合。

scala> val s = scala.collection.mutable.SortedSet[String]()
s: scala.collection.mutable.SortedSet[String] = TreeSet()

scala> s +=("c")
res45: s.type = TreeSet(c)

scala> s +=("a")
res46: s.type = TreeSet(a, c)

scala> s +=("b")
res47: s.type = TreeSet(a, b, c)

从这可以看出来SortedSet集合中的元素是按照元素的字典顺序排序的。

针对里面这些Set集合,如果想要迭代他们里面的元素,可以使用for循环直接迭代 以SortedSet为例,其它的Set、HashSet、LinkedHashSet都是一样的

scala> for(i <- s ) println(i)
a
b
c

4.List

List属于Seq接口的子接口,List代表一个不可变的列表。

scala>  val l = List(1, 2, 3, 4)
l: List[Int] = List(1, 2, 3, 4)

针对List有head、tail以及::这几个操作。

scala> l.head
res49: Int = 1

scala> l.tail
res51: List[Int] = List(2, 3, 4)

通过::操作符,可以将head和tail的结果合并成一个List。

scala> l.head :: l.tail
res52: List[Int] = List(1, 2, 3, 4)

在这里List是不可变的列表,在实际工作中使用的时候会很不方便,因为我们很多场景下都是需要向列表中动态添加元素,这个时候该怎么办呢?Scala还提供的有一个ListBuffer,ListBuffer:可以支持动态增加或者移除元素。

scala> val lb = scala.collection.mutable.ListBuffer[Int]()
lb: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala> lb +=1
res56: lb.type = ListBuffer(1)

scala> lb +=2
res57: lb.type = ListBuffer(1, 2)

scala> lb +=5
res58: lb.type = ListBuffer(1, 2, 5)

scala> lb -=5
res59: lb.type = ListBuffer(1, 2)

5.Map

Map是一种可迭代的键值对(key/value)结构,Map分为可变和不可变,默认情况下使用的是不可变Map。


#创建一个不可变的Map
scala> val ages = Map("jack"->30,"tom"->25,"jessic"->23)
ages: scala.collection.immutable.Map[String,Int] = Map(jack -> 30, tom -> 25, jessic -> 23)

scala> ages("jack")
res100: Int = 30


#创建一个可变的Map

scala> val ages = scala.collection.mutable.Map("jack"->30,"tom"->25,"jessic"->23)
ages: scala.collection.mutable.Map[String,Int] = Map(jessic -> 23, jack -> 30, tom -> 25)

scala> ages("jack")
res101: Int = 30

查询操作。获取指定key对应的value,如果key不存在,会报错。

scala> val ages = scala.collection.mutable.Map(("jack",30),("tom",25),("jessic"->23))
ages: scala.collection.mutable.Map[String,Int] = Map(jessic -> 23, jack -> 30, tom -> 25)

scala> val age = ages("jack")
age: Int = 30

scala> val age = ages("jack1")
java.util.NoSuchElementException: key not found: jack1

所以在实际工作中这样直接获取不太好,如果遇到了不存在的key程序会报错,导致程序异常退出。 那是不是可以考虑在获取key的值之前,先判断key是否存在。可以使用contains函数检查key是否存在、 使用if-else语句,如果指定的key不存在,则返回一个默认值。

scala> val age = if (ages.contains("jack1")) ages("jack1") else 0
age: Int = 0

这样是没问题的,就是写起来有点麻烦了,有没有方便一点的用法呢?map中还有一个getOrElse函数。

scala> val age = ages.getOrElse("jack1", 0)
age: Int = 0

scala> val age = ages.getOrElse("jack", 0)
age: Int = 30

建议后期从map中获取数据都使用这个getOrElse函数。

更新map中的元素

scala> ages("jack") = 31

scala> ages
res104: scala.collection.mutable.Map[String,Int] = Map(jessic -> 23, jack -> 31, tom -> 25)

增加多个元素

scala> ages += ("hehe" -> 35, "haha" -> 40)
res105: ages.type = Map(hehe -> 35, jessic -> 23, jack -> 31, tom -> 25, haha -> 40)

移除元素

scala> ages -= "hehe"
res106: ages.type = Map(jessic -> 23, jack -> 31, tom -> 25, haha -> 40)

遍历


#遍历map的entrySet

scala> for ((key, value) <- ages) println(key + " " + value)
jessic 23
jack 31
tom 25
haha 40


#遍历map的key

scala> for (key <- ages.keySet) println(key)
jessic
jack
tom
haha

#遍历map的value

scala> for (value <- ages.values) println(value)
23
31
25
40

最后看一下Map的几个子类,HashMap、SortedMap和LinkedHashMap。

HashMap分为可变和不可变的,没有什么特殊之处,在这主要演示一下SortedMap和LinkedHashMap。

SortedMap是不可变的。

scala> val ages = scala.collection.immutable.SortedMap("b" -> 30, "a" -> 15, "c" -> 25)
ages: scala.collection.immutable.SortedMap[String,Int] = Map(a -> 15, b -> 30, c -> 25)

scala> ages
res112: scala.collection.immutable.SortedMap[String,Int] = Map(a -> 15, b -> 30, c -> 25)

LinkedHashMap是可变的。

scala> val ages = new scala.collection.mutable.LinkedHashMap[String, Int]()
ages: scala.collection.mutable.LinkedHashMap[String,Int] = Map()

scala> ages("b")=30

scala> ages("a")=15

scala> ages("c")=25

scala> ages
res116: scala.collection.mutable.LinkedHashMap[String,Int] = Map(b -> 30, a -> 15, c -> 25)

6.Array

Scala中Array的含义与Java中的数组类似,长度不可变。由于Scala和Java都是运行在JVM中,双方可以互相调用,因此Scala数组的底层实现就是Java的数组。数组初始化后,长度就固定下来了,而且元素全部根据其类型进行初始化。

scala> val a = new Array[Int](10)
a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

scala> a(0)
res65: Int = 0

scala> a(0)=1

scala> a(0)
res67: Int = 1

也可以直接使用Array()创建数组,元素类型自动推断。

scala> val a = Array("hello", "world")
a: Array[String] = Array(hello, world)

scala> a(0)
res68: String = hello

scala> val a1 = Array("hello", 30)
a1: Array[Any] = Array(hello, 30)

7.ArrayBuffer

Scala中ArrayBuffer与Java中的ArrayList类似,长度可变。 ArrayBuffer:添加元素、移除元素 如果不想每次都使用全限定名,则可以预先导入ArrayBuffer类。

scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer

#初始化

scala> val b = new ArrayBuffer[Int]()
b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()

#添加元素
#使用+=操作符,可以添加一个元素,或者多个元素

scala> b += 1
res69: b.type = ArrayBuffer(1)

scala> b += (2, 3, 4, 5)
res70: b.type = ArrayBuffer(1, 2, 3, 4, 5)

#使用insert()函数

scala> b.insert(3,30)

scala> b
res72: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 30, 4, 5)


#移除元素
#使用remove()函数可以移除指定位置的元素

scala> b.remove(1)
res73: Int = 2

scala> b
res74: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 30, 4, 5)

注意:Array与ArrayBuffer可以互相进行转换。

数组常见操作。

遍历Array和ArrayBuffer的两种方式。由于Array和ArrayBuffer都是有下标的,所以在迭代数组中元素的时候除了可以使用前面迭代集合的方式还可以使用下标迭代。

scala> val b=ArrayBuffer(1, 2, 3, 4, 5)
b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5)

scala>  for(i <- b) println(i)
1
2
3
4
5

scala> for(i <- 0 until b.length ) println(b(i))
1
2
3
4
5

#求和、求最大值

scala> val a = Array(3, 2, 1, 4, 5)
a: Array[Int] = Array(3, 2, 1, 4, 5)

scala> val sum = a.sum
sum: Int = 15

scala> val max = a.max
max: Int = 5

#数组排序

scala> scala.util.Sorting.quickSort(a)

scala> a
res99: Array[Int] = Array(1, 2, 3, 4, 5)

8.Tuple

Tuple:称之为元组,它与Array类似,都是不可变的,但与数组不同的是元组可以包含不同类型的元素,Tuple中的元素的下标从 1 开始。

注意:目前 Scala 支持的元组最大长度为 22 ,对于更大长度可以使用集合或数组。

scala> val t = (1, 3.14, "hehe")
t: (Int, Double, String) = (1,3.14,hehe)

scala> t._1
res117: Int = 1

scala> t._3
res118: String = hehe

小结:

Scala的集合体系中的数据结构,有的是可变的,有的是不可变的,有的是既是可变的又是不可变的,听起来有点乱,在这里我们总结一下:

还有两个编外人员:Array和Tuple