scala编程学习之十-数据结构(集合)

10.1数据结构特点
1)Scala同时支持不可变集合和可变集合
2)两个主要的包:

不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable

3)Scala默认采用不可变集合,对于几乎所有的集合类,Scala都同时提供了可变(mutable)和不可变(immutable)的版本
4)Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质,在Scala中集合有可变(mutable)和不可变(immutable)两种类型。

10.1.1可变集合和不可变集合举例
1)不可变集合:scala不可变集合,就是这个集合本身不能动态变化。(类似java的数组,是不可以动态增长的)
2)可变集合:可变集合,就是这个集合本身可以动态变化的。(比如:ArrayList , 是可以动态增长的)
3)代码

import java.util.ArrayList;

public class MutableImmutableDemo {
    public static void main(String[] args) {

        //不可变集合类似java的数组
        int[] nums = new int[3];
        nums[2] = 11; //?
        //nums[3] = 90; //,即不能动态的增长

//        String[] names = {"bj", "sh"};
//        System.out.println(nums + " " + names);
//
可变集合举例
        ArrayList al = new ArrayList<String>();
        al.add("zs");
        al.add("zs2");
        System.out.println(al + " " + al.hashCode()); //地址1
        al.add("zs3");
        System.out.println(al + " " + al.hashCode()); //地址2

    }
}

10.2不可变集合继承层次一览图
在这里插入图片描述
Scala不可变集合
继承关系一览图
小结:
1.Set、Map是Java中也有的集合
2.Seq是Java没有的,我们发现List归属到Seq了,因此这里的List就和java不是同一个概念了
3.我们前面的for循环有一个 1 to 3 ,就是IndexedSeq 下的Vector
4.String也是属于IndexeSeq
5.我们发现经典的数据结构比如Queue 和 Stack被归属到LinearSeq
6.大家注意Scala中的Map体系有一个SortedMap,说明Scala的Map可以支持排序
7.IndexSeq 和 LinearSeq 的区别[IndexSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引
集合,通过索引即可定位] [LineaSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找,它的价值在于应用到一些具体的应用场景 (电商网站, 大数据推荐系统 :最近浏览的10个商品)

10.3可变集合体现一览图
在这里插入图片描述
10.4数组-定长数组(声明泛型)
10.4.1第一种方式定义数组
这里的数组等同于Java中的数组,中括号的类型就是数组的类型

val arr1 = new Array[Int](10)

//赋值,集合元素采用小括号访问

arr1(1) = 7 

10.4.2代码演示

object ArrayDemo {
  def main(args: Array[String]): Unit = {
    val arr01 = new Array[Int](4) // //表示我创建一个数组,存放Int,大小4
    println(arr01.length) // 4

    println("arr01(0)=" + arr01(0)) //访问指定下标的元素
    for (i <- arr01) { //遍历
      println(i)
    }
    println("--------------------")
    arr01(3) = 10 //修改
    for (i <- arr01) {
      println(i)
    }



  }
}

10.4.3第二种方式定义数组
在定义数组时,直接赋值//使用apply方法创建数组对象

val arr1 = Array(1, 2,"hello")   

代码:

var arr02 = Array(1, 3, "xxx")
for (i <- arr02) {
println(i)
}

10.5数组-变长数组(声明泛型)
基本使用和应用案例

//定义/声明
val arr2 = ArrayBuffer[Int]()
//追加值/元素
arr2.append(7)
//重新赋值
arr2(0) = 7  

学习集合的流程(c[创建]
[查看元素,遍历]u[修改]d[删除])
案例演示+反编译
代码

import  scala.collection.mutable.ArrayBuffer
object ArrayBufferDemo {
  def main(args: Array[String]): Unit = {

    //创建了一个 ArrayBuffer[Any] => 可存放任何对象

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

    println("arr01(1)=" + arr01(1))//可以下标访问IndexedSeq
    for (i <- arr01) {
      println(i)
    }
    println(arr01.length) //3

    println("arr01.hash=" + arr01.hashCode())
    //追加元素 ,append支持可变参数
    arr01.append(90.0,13)
    println("arr01.hash=" + arr01.hashCode())

    arr01(1) = 89 //修改
    println("--------------------------")
    for (i <- arr01) {
      println(i)
    }
//
//    //删除
    arr01.remove(0) //表示将第一个元素删除

    println("--------------------------")
    for (i <- arr01) {
      println(i)
    }
    println("最新的长度=" + arr01.length)

  }
}

10.5.1变长数组的分析
1)ArrayBuffer是变长数组,类似java的ArrayList
2)val arr2 = ArrayBufferInt 也是使用的apply方法构建对象
3)def append(elems: A*) { appendAll(elems) } 接收的是可变参数.
4)每append一次,arr在底层会重新分配空间,进行扩容,arr2的内存地址会发生变化,也就成为新的ArrayBuffer

10.5.2定长数组与变长数组的转换
1)arr1.toBuffer //定长数组转可变数组
2)arr2.toArray //可变数组转定长数组

说明:
arr2.toArray 返回结果才是一个定长数组, arr2本身没有变化
arr1.toBuffer返回结果才是一个可变数组, arr1本身没有变化
代码

import scala.collection.mutable.ArrayBuffer

object Array2ArrayBuffer {
  def main(args: Array[String]): Unit = {
    val arr2 = ArrayBuffer[Int]()
    // 追加值
    arr2.append(1, 2, 3)
    println(arr2)

    //将arrayBuffer -> Array
    val newArr = arr2.toArray
    //如果希望将一个数组Array的内容输出,可以简单的使用mkString
    println(newArr.mkString(" "))

    val newArr2 = newArr.toBuffer
    newArr2.append(123)
    println(newArr2)
    //案例演示+说明

  }
}

10.6数组-多维数组
说明

//定义
val arr = Array.ofDim[Double](3,4)

说明:
arr 是一个二维数组
有三个元素[一维数组]
每个一维数组存放4个值

//赋值
arr(1)(1) = 11.11

代码

object MuArray {
  def main(args: Array[String]): Unit = {

    //array1是一个二维数组
    val array1 = Array.ofDim[Int](3, 4)
    array1(1)(1) = 9 //给(1)(1)
    //item 是一个一维数组
    for (item <- array1) {
      //继续变量item一维数组
      for (item2 <- item) {
        print(item2 + "\t")
      }
      println()
    }

    //传统方法
    for (i <- 0 to array1.length -1 ){
      for (j <- 0 to array1(i).length -1) {
        printf("array1[%d][%d]=%d\t",i,j,array1(i)(j))
      }
      println()
    }

    var arr2 = Array(Array(1,2), Array(4,5,6), Array("hello","北京"))

    println("===============")
    for (i <- 0 to arr2.length -1 ){
      for (j <- 0 to arr2(i).length -1) {
        printf("array1[%d][%d]=%s\t",i,j,arr2(i)(j))
      }
      println()
    }

  }
}

10.7数组-Scala数组与Java的List的互转
10.7.1Scala数组转Java的List

在项目开发中,有时我们需要将Scala数组转成Java数组,看下面案例:

import scala.collection.mutable.ArrayBuffer

object ArrayBuffer2JavaList {
  def main(args: Array[String]): Unit = {

    // Scala集合和Java集合互相转换
    val arr = ArrayBuffer("1", "2", "3")
    import scala.collection.JavaConversions.bufferAsJavaList
    //即这里的bufferAsJavaList是一个隐式函数
    /*
    implicit def bufferAsJavaList[A](b : scala.collection.mutable.Buffer[A]) : java.util.List[
     */
    val javaArr = new ProcessBuilder(arr) //为什么可以这样使用?
    val arrList = javaArr.command()
    println(arrList) //输出 [1, 2, 3]

  }
}

10.7.2Java的List转scala的Buffer

 //说明:asScalaBuffer 是一个隐式转换
    /*
    implicit def asScalaBuffer[A](l : java.util.List[A]) : scala.collection.mutable.Buffer[A]
     */
    import scala.collection.JavaConversions.asScalaBuffer
    
    import scala.collection.mutable
    // java.util.List ==> Buffer
    val scalaArr: mutable.Buffer[String] = arrList
    scalaArr.append("jack")
    println(scalaArr)

10.8元组Tuple-元组的基本使用
10.8.1基本介绍
元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。
说的简单点,就是将多个无关的数据封装为一个整体,称为元组, 最大的特点灵活,对数据没有过多的约束。 //需求-> 高效率

注意:元组中最大只能有22个元素

10.8.2元组的创建

 //说明
    //1. tuple 的类型是 Tuple3
    //2. 根据元素个数不同,对应的类型是 Tuple1----Tuple22
    //3. Tuple是一个整体,使用迭代器进行遍历
    //4. 访问Tuple的元素的方式是 tuple._1 .... tuple._3
    //5. 元组是scala推荐使用,在java没有
    /*
    final case class Tuple3[+T1, +T2, +T3](_1: T1, _2: T2, _3: T3)
  extends Product3[T1, T2, T3]
{
  override def toString() = "(" + _1 + "," + _2 + "," + _3 + ")"

}

     */
    //创建元组
    val tuple = (1, 2, "hello")

10.9元组Tuple-元组数据的访问

 //访问元组
    //1. 使用 _顺序号
    println(tuple._3) // "hello"
    //2. 使用
    println(tuple.productElement(2)) //下标是从0开始计算

10.10元组的遍历
Tuple是一个整体,遍历需要调其迭代器

//遍历元组[通过迭代器来遍历]
    for (i <- tuple.productIterator) {
      println("i=" + i)
    }

10.11列表 List-创建List
10.11.1基本介绍

Scala中的List 和Java List 不一样,在Java中List是一个接口,真正存放数据是ArrayList,而Scala的List可以直接存放数据,就是一个object,默认情况下Scala的List是不可变的,List属于序列Seq。

val List = scala.collection.immutable.List
object List extends SeqFactory[List]

10.11.2创建List的应用案例

object ListDemo01 {
  def main(args: Array[String]): Unit = {

    //集合在scala.collection.mutable(immutalbe)._ 为什么不引人包也能使用List

    //原因: package object scala 包中声明了
    //val List = scala.collection.immutable.List
    //val Nil = scala.collection.immutable.Nil
    
    val list01 = List(1, 2, 3) //创建时,直接分配元素  apply
    println(list01)
    val list02 = Nil  //空集合
    println(list02)

  }
}

10.11.3创建List的应用案例小结
1)List默认为不可变的集合
2)List 在 scala包对象声明的,因此不需要引入其它包也可以使用
3)val List = scala.collection.immutable.List
4)List 中可以放任何数据类型,比如 arr1的类型为 List[Any]
如果希望得到一个空列表,可以使用Nil对象, 在 scala包对象声明的,因此不需要引入其它包也可以使用

10.12列表 List-访问List元素

val value1 = list1(1) // 1是索引,表示取出第2个元素.
println(value1)

10.13列表 List-元素的追加
10.13.1基本介绍
向列表中增加元素, 会返回新的列表/集合对象。注意:Scala中List元素的追加形式非常独特,和Java不一样。

10.13.2方式1-在列表的最后增加数据
10.13.3方式2-在列表的最前面增加数据
案例演示

//定义了List
    var list1 = List(1, 2, 3, "abc")
    // :+运算符表示在列表的最后增加数据
    // 说明 1. :+ 符号 : 前是集合 + 后是元素
    val list2 = list1 :+ 4
    println(list1) //list1没有变化
    println(list2) //新的列表结果是 [1, 2, 3, "abc", 4]

    //给list向前面追加
    //说明 1. +: 符号 : 后是集合 + 前是元素
    val list3 = 100 +: list1
    println("list3=" + list3)

10.13.4方式3-在列表的最后增加数据

说明:
1)符号::表示向集合中 新建集合添加元素。
2)运算时,集合对象一定要放置在最右边,
3)运算规则,从右向左。
4)::: 运算符是将集合中的每一个元素加入到空集合中去, ::: 左右两边需要时集合.
应用案例:

 // :: 使用
    val list4 = List(1, 2, 3, "abc")
    // 操作步骤
    // 1. ()
    // 2. (List(1, 2, 3, "abc"))
    // 3. (6, List(1, 2, 3, "abc"))
    // 4. (5, 6, List(1, 2, 3, "abc"))
    // 5. (4, 5, 6, List(1, 2, 3, "abc"))
    val list5 = 4 :: 5 :: 6 :: list4 :: Nil
    println("list5=" + list5)




    // ::: 的使用
    //下面等价 4 :: 5 :: 6 :: list1
    var list6 = List(1, 2, 3, "abc")
    // 步骤
    // 1. ()
    // 2. (1, 2, 3, "abc")
    // 3. (6, 1, 2, 3, "abc")
    // 4. (5, 6, 1, 2, 3, "abc")
    // 5. (4, 5, 6, 1, 2, 3, "abc")
    val list7 = 4 :: 5 :: 6 :: list6 ::: Nil
    println("list7=" + list7)

10.14列表 ListBuffer
ListBuffer:ListBuffer是可变的list集合,可以添加,删除元素,ListBuffer属于序
列 //追一下继承关系即可 Seq var listBuffer = ListBuffer(1,2)

import scala.collection.mutable.ListBuffer

object ListBufferDemo {
  def main(args: Array[String]): Unit = {

    val lst0 = ListBuffer[Int](1, 2, 3)

    println("lst0(2)=" + lst0(2)) //访问指定元素
    for (item <- lst0) { //遍历
      println("item=" + item)
    }

    val lst1 = new ListBuffer[Int]
    lst1 += 4  //lst1(4)
    lst1.append(5) //lst1(4,5)


    //++ 表示的是加入的是集合中的各个元素
    lst0 ++= lst1 //lst0(1,2,3,4,5)
    val lst2 = lst0 ++ lst1 //lst2(1,2,3,4,5,4,5)
    val lst3 = lst0 :+ 5 // 单独的加入元素 (1,2,3,4,5,5)
    println("lst0=" + lst0)
    println("lst1=" + lst1)
    println("lst2=" + lst2)
    println("lst3=" + lst3)

    println("=====删除=======")
    println("lst1=" + lst1)
    lst1(0) = 888
    lst1.remove(1) //使用remove进行删除,(1)表示第二个元素
    for (item <- lst1) {
      println("item=" + item)
    }

  }
}

10.15队列 Queue-基本介绍
10.15.1队列的说明

1)队列是一个有序列表,在底层可以用数组或是链表来实现。
2)其输入和输出要遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
3)在Scala中,由设计者直接给我们提供队列类型使用。
4)在scala中, 有 scala.collection.mutable.Queue 和 scala.collection.immutable.Queue , 一般来说,我们在开发中通常使用可变集合中的队列

10.15.2队列 Queue-队列的创建
//说明: 这里的Int是泛型,表示q1队列只能存放Int类型
//如果希望q1可以存放其它类型,则使用 Any 即可。
val q1 = new mutable.Queue[Int]
println(q1)

10.16队列 Queue-队列元素的追加数据

10.16.1向队列中追加单个元素和List

//追加单个元素
    q1 += 1
    q1 += 2
    println(q1)

    q1 ++= List(4, 5, 6)

    println(q1)

    //如果希望加入一个List或者其他的类型,则需要将Queue的泛型指定为[Any]
    //q1 += List(8,9)

    println(q1)

10.17队列 Queue-删除和加入队列元素
说明:按照进入队列的顺序删除元素(队列先进先出)
代码;

 //dequeue的操作,是出队列(即将队列的头元素取出)
    val ele = q1.dequeue()
    println("ele=" + ele) //1
    println("q1=" + q1) // (2,4,5,6)

    //enqueue的操作,表示给队列尾部加入数据
    q1.enqueue(10,20,30)
    println("q1=" + q1) // (2,4,5,6,10,20,30)


    //head
    println("q1.head=" + q1.head) // 2
    //last
    println("q1.last=" + q1.last) // 30
    //tail的用法
    println(q1.tail.tail) //(5,6,10,20,30)
    println("q1=" + q1) // (2,4,5,6,10,20,30)

10.18返回队列中的元素
在这里插入图片描述
10.19映射 Map-基本介绍
10.19.1Java中的Map回顾

HashMap 是一个散列表(数组+链表),它存储的内容是键值对(key-value)映射,Java中的HashMap是无序的,key不能重复。案例演示:

public class TestJavaMap {
    public static void main(String[] args) {
        HashMap<String,Integer> hm = new HashMap();
        hm.put("no1", 100);
        hm.put("no2", 200);
        hm.put("no3", 300);
        hm.put("no4", 400);

        System.out.println(hm);
        System.out.println(hm.get("no2"));
    }
}

10.19.2Scala中的Map介绍

1)Scala中的Map 和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala中不可变的Map是有序的,可变的Map是无序的。
2)Scala中,有可变Map (scala.collection.mutable.Map) 和 不可变Map(scala.collection.immutable.Map)

10.20映射 Map-构建Map
10.20.1方式1-构造不可变映射

Scala中的不可变Map是有序,构建Map中的元素底层是Tuple2类型。
案例
val map1 = Map(“Alice” -> 10, “Bob” -> 20, “Kotlin” -> “北京”)
小结
1.从输出的结果看到,输出顺序和声明顺序一致
2.构建Map集合中,集合中的元素其实是Tuple2类型
3.默认情况下(即没有引入其它包的情况下),Map是不可变map
4.为什么说Map中的元素是Tuple2 类型 [反编译或看对应的apply]

10.20.2方式2-构造可变映射
//需要指定可变Map的包
val map2 = scala.collection.mutable.Map(“Alice” -> 10, “Bob” -> 20, “Kotlin” -> 30)
说明
1.从输出的结果看到,输出顺序和声明顺序不一致

10.20.3方式3-创建空的映射

val map3 = new scala.collection.mutable.HashMap[String, Int]
println(map3)

10.20.4方式4-对偶元组
即创建包含键值对的二元组, 和第一种方式等价,只是形式上不同而已。

对偶元组 就是只含有两个数据的元组。

val map4 = mutable.Map( ("A", 1), ("B", 2), ("C", 3),("D", 30) )
println("map4=" + map4)
println(map4("A"))

10.21映射 Map-取值
10.21.1方式1-使用map(key)

val value1 = map2("Alice") 
println(value1)

说明:
1)如果key存在,则返回对应的值
2)如果key不存在,则抛出异常[java.util.NoSuchElementException]
3)在Java中,如果key不存在则返回null

10.21.2方式2-使用contains方法检查是否存在key

// 返回Boolean
// 1.如果key存在,则返回true
// 2.如果key不存在,则返回false
map4.contains("B")

说明:
使用containts先判断在取值,可以防止异常,并加入相应的处理逻辑

val map4 = mutable.Map( ("A", 1), ("B", 2), ("C", 3),("D", 30.9) )
if( map4.contains("B") ) {
println("key存在 值= " + map4("B"))
} else {
println("key不存在")
}

10.21.3方式3-使用map.get(key).get取值
通过 映射.get(键) 这样的调用返回一个Option对象,要么是Some,要么是None

var map4 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) )
println(map4.get("A")) //Some
println(map4.get("A").get) //得到Some在取出

说明和小结:
1)map.get方法会将数据进行包
2)如果 map.get(key) key存在返回some,如果key不存在,则返回None
3)如果 map.get(key).get key存在,返回key对应的值,否则,抛出异常 java.util.NoSuchElementException: None.get

10.21.4方式4-使用map4.getOrElse()取值

getOrElse 方法 : def getOrElse[V1 >: V](key: K, default: => V1)
说明:
如果key存在,返回key对应的值。
如果key不存在,返回默认值。在java中底层有很多类似的操作。

val map4 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) )
println(map4.getOrElse("A","默认"))

10.21.5如何选择取值方式建议
1)如果我们确定key是存在的,应该使用map(“key”) ,速度快.
2)如果我们不确定key是否存在, 而且在不存在时,有业务逻辑处理就是用map.contains() 配合 map(“key”)
3)如果只是简单的希望返回一个值,就使用getOrElse()

10.22映射 Map-对map修改、添加和删除
10.22.1更新map的元素

案例:

val map4 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) )
	map4("A") = 20 //修改和增加
	println(map4)

说明:

1)map 是可变的,才能修改,否则报错
2)如果key存在:则修改对应的值,key不存在,等价于添加一个key-val

10.22.2添加map元素
在这里插入图片描述
10.22.3删除map元素
在这里插入图片描述
提示:map4.remove(key)

10.23映射 Map-对map遍历

map的遍历支持多种形式:
val map1 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) )
for ((k, v) <- map1) println(k + " is mapped to " + v)
for (v <- map1.keys) println(v)
for (v <- map1.values) println(v) //早上 
for(v <- map1) println(v) //v是Tuple2

说明
1.每遍历一次,返回的元素是Tuple2
2.取出的时候,可以按照元组的方式来取

10.24集 Set-基本介绍

10.24.1集是不重复元素的结合。集不保留顺序,默认是以哈希集实现

10.24.2Java中Set的回顾

java中,HashSet是实现Set接口的一个实体类,数据是以哈希表的形式存放的,里面的不能包含重复数据。Set接口是一种不包含重复元素的 collection,HashSet中的数据也是没有顺序的。

public class JavaSet {
    public static void main(String[] args) {
        HashSet hs = new HashSet<String>();
        hs.add("jack");
        hs.add("tom");
        hs.add("jack");
        hs.add("jack2");
        System.out.println(hs);

    }
}

10.24.3Scala中Set的说明

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

10.24.4Scala的可变Set和不可变Set的举例

import scala.collection.mutable

object ScalaSet01 {
  def main(args: Array[String]): Unit = {
    val set01 = Set(1,2,4,"abc")
    println(set01)
    val set02 = mutable.Set(1,2,4,"abc")
    println(set02)
  }
}

10.25集 Set-可变集合的元素添加和删除
在这里插入图片描述
10.25.1可变集合的元素删除

val set02 = mutable.Set(1,2,4,"abc")
set02 -= 2 // 操作符形式
set02.-=(4) // ok
set02.remove("abc") // 方法的形式,scala的Set可以直接删除值
println(set02)

说明:说明:如果删除的对象不存在,则不生效,也不会报错

10.25.2set集合的遍历

val set02 = mutable.Set(1, 2, 4, "abc")
for(x <- set02) {
println(x)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值