添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

序列的操作有以下几种:

  • 索引和长度的操作 apply、isDefinedAt、length、indices,及lengthCompare。序列的apply操作用于索引访问;因此,Seq[T]类型的序列也是一个以单个Int(索引下标)为参数、返回值类型为T的偏函数。换言之,Seq[T]继承自Partial Function[Int, T]。序列各元素的索引下标从0开始计数,最大索引下标为序列长度减一。序列的length方法是collection的size方法的别名。lengthCompare方法可以比较两个序列的长度,即便其中一个序列长度无限也可以处理。
  • 索引检索操作 (indexOf、lastIndexOf、indexofSlice、lastIndexOfSlice、indexWhere、lastIndexWhere、segmentLength、prefixLength)用于返回等于给定值或满足某个谓词的元素的索引。
  • 加法运算 (+:,:+,padTo)用于在序列的前面或者后面添加一个元素并作为新序列返回。
  • 更新操作 (updated,patch)用于替换原序列的某些元素并作为一个新序列返回
  • 排序操作 (sorted, sortWith, sortBy)根据不同的条件对序列元素进行排序。
  • 反转操作 (reverse, reverseIterator, reverseMap)用于将序列中的元素以相反的顺序排列。
  • 比较 (startsWith, endsWith, contains, containsSlice, corresponds)用于对两个序列进行比较,或者在序列中查找某个元素。
  • 多集操作 (intersect, diff, union, distinct)用于对两个序列中的元素进行类似集合的操作,或者删除重复元素。
  • Seq 在 Iterator 的基础上添加了其他一些操作 :

    Seq trait 具有三个子特征(subtrait):

  • 线性序列(LinearSeq):不添加新的操作,具有高效的 head 和 tail 操作,常用线性序列有 scala.collection.immutable.List scala.collection.immutable.Stream
  • 索引序列(IndexedSeq):不添加新的操作,具有高效的apply, length, 和 (如果可变) update操作,常用索引序列有 scala.collection.mutable.ArrayBuffer scala.collection.immutable.Vector
  • 缓冲器(Buffer):缓冲器允许对现有元素进行增、删、改操作,常用的Buffer序列有 ListBuffer ArrayBuffer ,Buffer 在 Seq 的基础上增加了一些添加和删除的操作;
  • 列表(List)

    List 是一个不可变链表,它既不能调整大小也不能改变其内容/状态。

    List 的创建

    创建列表的标准做法

    Scala中创建List或者其他类型集合时,标准做法是作为一个函数来调用这个集合,并提供必要的内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    scala> val colors = List("red", "green", "blue")
    colors: List[String] = List(red, green, blue)

    scala> val nums: List[List[Int]] =
    | List(
    | List(1, 0, 0),
    | List(0, 1, 0),
    | List(0, 0, 1)
    | )
    nums: List[List[Int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))

    Scala 的列表类型是协变的(covariant),对每一组类型的S和T,如果S是T的子类型,那么List[S]就是List[T]的子类型。空列表的类型是List[Nothing],对任何T来说,List[Nothing] 都是List[T]的子类型,这也是为什么编译器允许我们编写一下代码:

    1
    2
    3
    4
    5
    scala> val x = List()
    x: List[Nothing] = List()

    scala> val s: List[String] = List()
    s: List[String] = List()

    创建列表的构建单元

    所有列表都构建自两个基础的构建单元: Nil :: Nil 表示空列表,中缀表达式 :: 表示在列表前追加元素,List(…)不过是最终展开成这些定义的包装方法而已

    1
    2
    3
    // 以:结束的操作符是右结合的,等价于val colors = ("red" :: ("green" :: ("blue" :: Nil)))
    scala> val colors = "red" :: "green" :: "blue" :: Nil
    colors: List[String] = List(red, green, blue)

    List 的基本操作

    列表原始操作

    List 的所有操作都可以用下面三个原始操作来完成:

  • head 返回列表的第一个元素,对空列表将抛出异常
  • tail 返回列表中除第一个元素之外的所有元素,对空列表将抛出异常
  • isEmpty 返回列表是否为空列表
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    scala> val emptyList = Nil
    emptyList: scala.collection.immutable.Nil.type = List()

    scala> emptyList.head
    java.util.NoSuchElementException: head of empty list
    at scala.collection.immutable.Nil$.head(List.scala:430)
    ... 28 elided

    scala> emptyList.tail
    java.lang.UnsupportedOperationException: tail of empty list
    at scala.collection.immutable.Nil$.tail(List.scala:432)
    ... 28 elided

    scala> emptyList.isEmpty
    res6: Boolean = true

    scala> colors.head
    res7: String = red

    scala> colors.tail
    res8: List[String] = List(green, blue)

    与 head 和 tail 方法对应,List还提供了相应的对偶方法,last 获取列表的最后一个元素,init返回除了最后一个元素之外的剩余部分,所不同的是后两种方法的时间复杂度为 O(n)

    1
    2
    3
    4
    5
    6
    7
    8
    scala> val abc = List('a', 'b', 'c')
    abc: List[Char] = List(a, b, c)

    scala> abc.last
    res14: Char = c

    scala> abc.init
    res3: List[Char] = List(a, b)

    列表解构

    列表支持解构:

    1
    2
    3
    4
    scala> val List(a, b, c) = colors
    a: String = red
    b: String = green
    c: String = blue

    列表解构可以用于模式匹配: x :: xs 是中缀操作模式的一个特例,中缀操作等同于一次方法调用,而 :: 作为模式有着不同的规则,它是被当做构造方法模式处理的, x::xs 相当于 ::(x, xs) ,Scala中有一个类叫 scala.:: 就是用来构建非空列表的。通常,对列表做模式匹配比用方法来解构更清晰,下面是一个使用列表的模式匹配实现插入排序的一个例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 插入排序
    def isort(xs: List[Int]): List[Int] = xs match {
    case List() => List()
    case x :: xs1 => insert(x, isort(xs1))
    }

    def insert(x: Int, xs: List[Int]): List[Int] = xs match {
    case List() => List(x)
    case y :: ys => if (x <= y) x:: xs else y :: insert(x, ys)
    }

    val l = List(2,3,1)

    println(isort(l))
    List(1, 2, 3)

    List 的初阶方法

    List 继承了 Seq 特质(LinearSeq 没有添加新的操作)中不可变类型的所有方法,此外 List 还增加了一些自身独有的操作。

    索引和长度

    1
    
    
    
    
        
    
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    scala> val abc = List('a', 'b', 'c')
    abc: List[Char] = List(a, b, c)

    // 按索引获取元素:当对象出现在方法调用中函数出现的位置时,编译器会帮我们插入apply
    scala> abc.apply(1)
    res4: Char = b
    scala> abc(1)
    res5: Char = b

    // 获取列表长度:length 和 size 方法都可以返回列表长度
    scala> abc.length
    res13: Int = 3
    scala> abc.size
    res14: Int = 3

    // 获取索引范围:indices属性返回列表的索引范围(0~list.size-1)
    scala> abc.indices
    res43: scala.collection.immutable.Range = Range 0 until 3

    // 获取列表切片:`xs.slice(start, end)` 返回列表的一个连续部分,从第一个索引到第二个索引(不包含第二个索引)
    scala> List(1,2,3,4,5).slice(1,3)
    res5: List[Int] = List(2, 3)

    // 获取列表前缀
    scala> abc.take(2)
    res9: List[Char] = List(a, b)
    // 获取列表后缀
    scala> abc.drop(2)
    res8: List[Char] = List(c)
    // splitAt(n) 将列表从指定下标切开,返回这两个列表组成的元组,元组的第一个列表长度为 n
    scala> abc.splitAt(1)
    res16: (List[Char], List[Char]) = (List(a),List(b, c))

    按索引查找

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    scala> val list = List(1,2,4,3,2,4)
    list: List[Int] = List(1, 2, 4, 3, 2, 4)
    // 返回序列xs中等于x的第一个元素的索引
    scala> list.indexOf(2)
    res50: Int = 1
    // 返回序列xs中等于x的最后一个元素的索引
    scala> list.lastIndexOf(2)
    res51: Int = 4
    // 查找子序列ys,返回xs中匹配的第一个索引
    scala> list.indexOfSlice(List(2,4))
    res52: Int = 1
    // xs序列中满足p的第一个元素
    scala> list.indexWhere(_ > 2)
    res53: Int = 2

    列表加法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    scala> val y = List(4,5)
    y: List[Int] = List(4, 5)

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

    scala> val ys = List(4,5)
    ys: List[Int] = List(4, 5)

    scala> val x = 0
    x: Int = 0

    // 在列表xs首部插入一个元素x,返回一个新的列表
    scala> x +: xs
    res54: List[Int] = List(0, 1, 2, 3)
    // 在列表xs尾部插入一个元素x,返回一个新的列表
    scala> xs :+ x
    res55: List[Int] = List(1, 2, 3, 0)

    // 在列表ys首部插入另一个集合,返回一个新的列表
    scala> xs ++: ys
    res56: List[Int] = List(1, 2, 3, 4, 5)
    // 在列表xs尾部插入另一个集合,返回一个新的列表
    scala> xs ++ ys
    res58: List[Int] = List(1, 2, 3, 4, 5)
    // 拼接列表xs和ys,以上三种形式最终效果等价,但:::要求左右两个操作数均为列表
    scala> xs ::: ys
    res62: List[Int] = List(1, 2, 3, 4, 5)

    更新

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    scala> xs
    res71: List[Int] = List(1, 2, 3)

    scala> ys
    res72: List[Int] = List(4, 5)

    // 将xs中索引为i的元素替换为x,返回一个新的列表
    scala> xs.updated(1, 9)
    res75: List[Int] = List(1, 9, 3)

    // 将xs中slice(i,j)的切片替换为序列 Seq ys
    scala> xs.patch(0, ys, 3)
    res76: List[Int] = List(4, 5)
    scala> xs.patch(0, ys, 0)
    res78: List[Int] = List(4, 5, 1, 2, 3)
  • xs.sorted:按自然值对核心类型的列表排序(升序),返回一个新列表
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 对数值型来说就是值的大小
    scala> List(2,1,3).sorted
    res8: List[Int] = List(1, 2, 3)

    scala> List('a','A','b').sorted
    res80: List[Char] = List(A, a, b)

    // 对字符串来说是其字典序
    scala> List("w", "da", "h").sorted
    res9: List[String] = List(da, h, w)
  • sortBy: xs.sortBy(f) 接收一个列表xs,对每个元素调用函数 f,按照函数返回值的自然值对列表中的元素进行排序(升序)
  • 1
    2
    scala> List("w", "da", "h").sortBy(_.size)
    res10: List[String] = List(w, h, da)
  • sortWith: xs.sortWith(before) 接收一个列表 xs,before是一个用来比较两个元素的布尔函数, x before y 返回true则代表x应该排列在y前面
  • 1
    
    
    
    
        
    
    2
    scala> List(1, -3 ,4, 2).sortWith(_ < _)
    res77: List[Int] = List(-3, 1, 2, 4)
  • 列表反转:由于列表是一个链表,当需要频繁访问列表的末尾时,先将列表反转,操作结束再对反转后的列表进行反转通常是更好的选择
  • 1
    2
    3
    4
    5
    6
    7
    8
    scala> abc.reverse
    res10: List[Char] = List(c, b, a)

    scala> abc.reverse.head
    res11: Char = c

    scala> abc.reverse.tail
    res12: List[Char] = List(b, a)

    比较

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 测试序列xs是否以序列ys开头
    scala> xs.startsWith(ys)
    res85: Boolean = false
    // 测试序列xs是否以序列ys结尾
    scala> xs.endsWith(ys)
    res86: Boolean = true
    // 测试xs序列中是否存在一个与x相等的元素
    scala> xs.contains(1)
    res88: Boolean = true
    // 测试xs序列中是否存在一个与ys相同的连续子序列
    scala> xs.containsSlice(ys)
    res89: Boolean = true
  • 集合操作:并非真的”集合“操作,因为不去重
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    scala> val xs = List(1,1,2,1,3,2,3)
    xs: List[Int] = List(1, 1, 2, 1, 3, 2, 3)

    scala> val ys = List(1,2,1,4,5)
    ys: List[Int] = List(1, 2, 1, 4, 5)

    // 序列xs和ys的交集,并保留序列xs中的顺序,遍历xs中的元素,在ys中查找,找不到就pass,找到保留,并从ys中去掉这个元素,重复以上过程
    scala> xs intersect ys
    res97: List[Int] = List(1, 1, 2)
    // 序列xs和ys的差集,并保留序列xs中的顺序,遍历xs中的元素,在ys中查找,找到就pass,找不到保留,并从ys中去掉这个元素,重复以上过程
    scala> xs diff ys
    res98: List[Int] = List(1, 3, 2, 3)
    // 并集;同xs ++ ys
    scala> xs union ys
    res96: List[Int] = List(1, 1, 2, 1, 3, 2, 3, 1, 2, 1, 4, 5)
    // 去重
    scala> xs.distinct
    res99: List[Int] = List(1, 2, 3)
  • 列表扁平化:flatten 方法接收一个列表的列表并将它扁平化,返回单个列表
  • 1
    2
    3
    4
    5
    scala> val efg = List('e', 'f', 'g')
    efg: List[Char] = List(e, f, g)

    scala> List(abc, efg).flatten
    res18: List[Char] = List(a, b, c, e, f, g)
  • 列表拉链/解拉链:zip 方法接收两个列表,一一匹配两个列表中的元素,返回一个元组列表,如果两个列表长度不同则会丢弃没有匹配上的元素;
  • 1
    2
    scala> abc.zip(efg)
    res19: List[(Char, Char)] = List((a,e), (b,f), (c,g))
  • 列表解拉链:unzip 方法是zip的逆方法,接收一个元组列表,返回一个列表元组
  • 1
    2
    scala> abc.zip(efg).unzip
    res20: (List[Char], List[Char]) = (List(a, b, c),List(e, f, g))

    var列表赋值

    不可变集合同样提供了 += 和 -= 操作,虽然效果相同,但它们在实现上是不同的。可变集合的+=是在可变集合上调用+=方法,它会改变s的内容;但不可变类型的+=却是赋值操作的简写,它是在集合上应用方法+,并把结果赋值给集合变量。这体现了一个重要的原则:我们通常能用一个非不可变集合的变量(var)来替换可变集合的常量(val)。

    列表虽然是不可变的,但是可以通过重新赋值来改变列表变量的值,从最终结果来看与使用可变类型相同,但有效率上的差异。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    scala> var xs = List[Int]()
    xs: List[Int] = List()

    scala> val ys = List(1,2)
    ys: List[Int] = List(1, 2)
    // += 操作
    scala> xs +:= 0

    scala> xs
    res112: List[Int] = List(0)

    scala> xs :+= 3

    scala> xs
    res114: List[Int] = List(0, 3)

    scala> xs ++= ys

    scala> xs
    res116: List[Int] = List(0, 3, 1, 2)

    scala> xs :::= ys

    scala> xs
    res118: List[Int] = List(1, 2, 0, 3, 1, 2)
    // 普通赋值
    scala> xs = xs.updated(0,9)
    xs: List[Int] = List(9, 2, 0, 3, 1, 2)

    scala> xs
    res119: List[Int] = List(9, 2, 0, 3, 1, 2)

    scala> xs = xs.sorted
    xs: List[Int] = List(0, 1, 2, 2, 3, 9)

    scala> xs
    res120: List[Int] = List(0, 1, 2, 2, 3, 9)

    转换列表

    列表无处不在,需要集合时推荐优先使用List,Scala的集合类型可以很容易的进行相互转换

  • toString 返回列表的标准字符串表现形式;
  • 1
    2
    scala> abc.toString
    res16: String = List(a, b, c)
  • mkString(pre, sep, post) 通过分隔符seq拼接列表中的元素,然后再首位添加前缀pre和后缀;
  • 1
    
    
    
    
        
    
    2
    3
    4
    5
    6
    7
    8
    scala> abc.mkString("[", ",", "]")
    res23: String = [a,b,c]

    scala> abc.mkString(",")
    res24: String = a,b,c

    scala> abc.mkString("")
    res26: String = abc
  • toArray:将列表转化为数组(顺序表)
  • 1
    2
    scala> abc.toArray
    res36: Array[Char] = Array(a, b, c)
  • copyToArray:将列表中的元素依次复制到目标数组的指定位置
  • 1
    2
    3
    4
    5
    6
    7
    scala> val arr = new Array[Char](10)
    ?[1m?[34marr?[0m: ?[1m?[32mArray[Char]?[0m = Array(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

    scala> abc.copyToArray(arr, 3)

    scala> arr
    ?[1m?[34mres35?[0m: ?[1m?[32mArray[Char]?[0m = Array(?, ?, ?, a, b, c, ?, ?, ?, ?)
  • iterator:将列表转化为迭代器
  • 1
    2
    scala> abc.iterator
    res37: Iterator[Char] = <iterator>

    List 的高阶方法

    列表映射(map):