Scala笔记整理(六):Scala集合库

[TOC]


Scala主要集合结构

1、Scala中的集合体系主要包括:IterableSeq(IndexSeq)Set(SortedSet)Map(SortedMap)。其中Iterable是所有集合trait的根trait。实际上Seq、Set、和Map都是子trait

  • Seq

    是一个有先后次序的值的序列,比如数组或列表。IndexSeq允许我们通过×××的下表快速的访问任意元素。举例来说,ArrayBuffer是带下标的,但是链表不是。

  • Set

    是一组没有先后次序的值。在SortedSet中,元素以某种排过序顺序被访问。

  • Map

    是一组(键、值)对偶。SortedMap按照键的排序访问其中的实体。

2、 Scala中的集合是分成可变和不可变两类集合的,其中可变集合就是说,集合的元素可以动态修改,而不可变集合的元素在初始化之后,就无法修改了。分别对应scala.collection.mutablescala.collection.immutable两个包。

3、Seq下包含了RangeArrayBufferList等子trait。其中Range就代表了一个序列,通常可以使用“1 to10”这种语法来产生一个Range。 ArrayBuffer就类似于Java中的ArrayList。

List

List常用操作1

1、在Scala中,列表要么是Nil(及空表),要么是一个head元素加上一个tail,而tail又是一个列表

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

scala> list.head
res29: Int = 1

scala> list.tail
res30: List[Int] = List(2, 3, 4, 5)

scala> list.isEmpty
res31: Boolean = false

scala> list == Nil
res32: Boolean = false

下面是一个使用递归求list集合中和的例子:

def recursion(list:List[Int]):Int = {
    if(list.isEmpty) {
        return 0  // 使用return显式结束程序的运行,否则0只是该if语句的返回值,并不会结束程序的运行,当然如果用else不用return也行
    }
    list.head + recursion(list.tail)
}

List常用操作2

增加
//增
/*  A.++(B)  --> 在列表A的尾部对添加另外一个列表B,组成一个新的列表
 *  A.++:(B) --> 在列表A的首部对添加另外一个列表B,组成一个新的列表
 *  A.:::(B) --> 在列表A的首部对添加另外一个列表B,组成一个新的列表
 *  ------
 *  A.:+ (element) -->在列表A的尾部添加一个element,组成一个新的集合
 *  A.+: (element) -->在列表A的首部添加一个element,组成一个新的集合
 *  A.:: (element) -->在列表A的首部添加一个element,组成一个新的集合
 */

测试如下:

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

scala> val right = List(5, 6, 7)
right: List[Int] = List(5, 6, 7)

scala> left.++(right)
res33: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> left.++:(right)
res34: List[Int] = List(5, 6, 7, 1, 2, 3, 4)

scala> left.:::(right)
res35: List[Int] = List(5, 6, 7, 1, 2, 3, 4)

scala> left.:+(10)
res36: List[Int] = List(1, 2, 3, 4, 10)

scala> left.+:(10)
res38: List[Int] = List(10, 1, 2, 3, 4)

scala> left.::(10)
res39: List[Int] = List(10, 1, 2, 3, 4)
删除
drop(n)         --->删除list的前n个元素(首部开始删除)
dropRight(n)    --->删除list的后n个元素(尾部开始删除)
dropWhile(p: A => Boolean)  --->逐个匹配去除符合条件的元素,直到不符合条件,之后的元素不再判断

测试如下:

scala> val list = List(1, 2, 3, 4, 5, 6, 7)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> list.drop(2)
res52: List[Int] = List(3, 4, 5, 6, 7)

scala> list.dropRight(3)
res53: List[Int] = List(1, 2, 3, 4)

scala> list.dropWhile(_ <= 3)
res54: List[Int] = List(4, 5, 6, 7)

scala> list.dropWhile(_ > 3)    // 第一个元素就不符合条件,后面的不再判断,所以一个也没有删除
res55: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
修改与查询
scala> val list = List(1, 2, 3, 4, 5, 6, 7)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> list(0)
res57: Int = 1

scala> list(0) = 10
<console>:9: error: value update is not a member of List[Int]
              list(0) = 10
              ^

默认的List是在:

scala> List
res59: scala.collection.immutable.List.type = scala.collection.immutable.List$@3e98fd35

所以不能修改,但是尝试导入可修改的List也不能进行导入:

scala> import scala.collection.mutable.List
<console>:8: error: object List is not a member of package scala.collection.mutable
       import scala.collection.mutable.List

原因如下:

Scala 列表类似于数组,它们所有元素的类型都相同,但是它们也有所不同:
列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。

List常用操作3

scala> val list = List(1, 2, 3, 4, 5, 6, 7)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> list.take(5)
res60: List[Int] = List(1, 2, 3, 4, 5)

scala> list.takeWhile(_ <= 3)
res61: List[Int] = List(1, 2, 3)

scala> list.takeWhile(_ > 3)
res62: List[Int] = List()

scala> list.mkString
res63: String = 1234567

scala> list.count(_ % 2 == 0)
res64: Int = 3

scala> val fruit = "apples" :: ("oranges" :: ("pears" :: Nil))  // ::操作符从给定的头和尾部创建一个新的列表
fruit: List[String] = List(apples, oranges, pears)

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

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

scala> list1 ++ list2   // ++两个集合之间的操作
res70: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> list1.sum
res72: Int = 6

Set

1、数据集是不重复元素的集合。尝试将已有元素加入进来是没有效果的。比如

def setOps:Unit ={
    (Set(2,0,1) + 1).foreach(println(_))
}

2、Set不保留元素插入的顺序。缺省情况下,集是以哈希集实现的,其元素根据hashCode方法的值进行组织。

Set(1,2,3,5,7,8).foreach(println(_))

3、链式哈希集可以记住元素被插入的顺序。它会维护一个链表来达到这个目的。

val weeks= scala.collection.mutable.LinkedHashSet("Mo","Tu","We","Th","Fr")
weeks.foreach(println(_))

4、按照已排序的顺序来访问其中的元素

scala.collection.immutable.SortedSet(1,2,3,4,5,6).foreach(println(_))

set集合顺序说明

直接看下面的测试代码及注释:

package cn.xpleaf.bigdata.p4.collection

import scala.collection.mutable.SortedSet

object _02CollectionOps {
  def main(args: Array[String]): Unit = {
    setOps1
  }

  /**
    * 关于scala集合顺序的说明
    *     测试1:按照年龄进行升序,年龄相等,姓名降序
    *     测试2:要按照姓名升序比较,按照年龄升序比较
    * SortedSet在添加普通对象Person之类,报错
    *   No implicit Ordering defined for Person
    *   要想在有序集合中添加元素,必须要让元素具备比较性,要和给集合提供比较器
    *   在java中前者是要类实现Comparator,后者需要给集合提供一个比较器Comparator
    *   在scala中,前者需要让类扩展Ordered的特质,后者给集合传递一个Ordering比较器
    *
    *   当两个比较都实现的话,优先使用集合的比较器
    */
  def setOps1: Unit = {
    var set = SortedSet[Person]()(new Ordering[Person] {
      override def compare(x: Person, y: Person):Int = {
        var ret = x.getName.compareTo(y.getName)
        if(ret == 0) {
          ret = x.getAge.compareTo((y.getAge))
        }
        ret
      }
    })
    set.+= (new Person("王立鹏", 19))
    set.+= (new Person("冯 剑", 18))
    set.+= (new Person("刘银鹏", 15))
    set.+= (new Person("李小小", 19))
    // println(set)
    set.foreach(println(_))
  }
}

class Person extends Ordered[Person] {
  private var name:String = _

  private var age:Int = _

  def this(name:String, age:Int) {
    this()
    this.name = name
    this.age = age
  }

  def getAge = age

  def getName = name

  override def toString: String = {
    s"[$name, $age]"
  }

  /**
    * 按照年龄进行升序,年龄相等,姓名降序
    * 升序:前面比后面
    * 降序:后面比前面
    */
  override def compare(that: Person) = {
    var ret = this.age.compareTo(that.age)
    if(ret == 0) {
      ret = that.name.compareTo(this.name)
    }
    ret
  }
}

输出结果如下:

[冯 剑, 18]
[刘银鹏, 15]
[李小小, 19]
[王立鹏, 19]

集合的函数式编程

1、集合的函数式编程非常之重要,这是我们以后工作中每天都在使用的编程方式。

2、必须完全掌握和理解Scala的高阶函数是什么意思,Scala的集合类的map、flatMap、reduce、reduceLeft、foreach等这些函数,就是高阶函数,因为可以接收其他函数作为参数(部分高阶函数可以参考前面整理的函数式编程笔记)

3、高阶函数的使用,也是Scala与Java最大的一点不同!!!因为Java在1.8之前是没有函数式编程的,也肯定没有高阶函数,也肯定无法直接将函数传入一个方法,或者让一个方法返回一个函数

4、对Scala高阶函数的理解、掌握和使用,可以大大增强你的技术,而且也是Scala最有诱惑力、最有优势的一个功能。

5、在Spark源码中,有大量的函数式编程,所以必须掌握,才能看懂spark源码。

  • foreach方法可以将某个函数应用到集合中的每个元素并产生结果的集合
scala> val names = List("Peter","Paul","Mary")
names: List[String] = List(Peter, Paul, Mary)

scala>  names.map(_.toUpperCase).foreach(println(_))
PETER
PAUL
MARY
  • Map函数每个后面都加上一个==》
scala> List("Peter","Paul","Mary").map(_ + "===>name").foreach(println(_))
Peter===>name
Paul===>name
Mary===>name
  • Flatmap按照空格进行划分
scala> List("Peter Glad","Paul Hello","Mary Your").flatMap(_.split(" ")).foreach(println)
Peter
Glad
Paul
Hello
Mary
Your

原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/186468.html

(0)
上一篇 2021年11月4日
下一篇 2021年11月4日

相关推荐

发表回复

登录后才能评论