Scala集合
Posted 岱宗夫如何、
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala集合相关的知识,希望对你有一定的参考价值。
目录
类型
序列 Seq 、集 Set 、映射 Map 都扩展自 Iterable 特质 都分为 了 可变 和 不可变 的版本不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable
不可变集合
指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象可变集合
集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java 中 StringBuilder 对象 建议:在操作集合的时候,不可变用符号,可变用方法IndexedSeq 和 LinearSeq 的区别:
IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位
LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
数组
不可变
val arr =new Array[类型](大小)
val arr01 = new Array[Int](4)
println(arr01.length) // 4
//(2)数组赋值
//(2.1)修改某个元素的值
arr01(3) = 10
//(2.2)采用方法的形式给数组赋值
arr01.update(0, 1) //将第0个数赋值为1
//(3)遍历数组
//(3.1)查看数组
println(arr01.mkString(","))
//(3.2)普通遍历
for (i <- arr01)
println(i)
//(3.3)简化遍历
def printx(elem: Int): Unit =
println(elem)
arr01.foreach(printx)
// arr01.foreach((x)=>println(x))
// arr01.foreach(println(_))
arr01.foreach(println)
//(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数组)
println(arr01)
val ints: Array[Int] = arr01 :+ 5 //末尾追加
val ints1: Array[Int] = arr01 +: 5 //头部追加
println(ints)
//如果使用空格 替换掉 “.” 的时候,如果后面的操作符是以":" 号结尾的,那操作符是从右边往左边的
val new = Arr :+ 15
val new1 = 15 +: Arr
// 19 +: 32 +: Arr
第二种方式定义数组
val arr1 = Array (1, 2)
(1)在定义数组时,直接赋初始值
(2)使用 apply 方法创建数组对象
object TestArray
def main(args: Array[String]): Unit =
var arr02 = Array(1, 3, "bobo")
println(arr02.length)
for (i <- arr02)
println(i)
可变数组
import scala.collection.mutable.ArrayBuffer
val arr01 = ArrayBuffer[Any](3, 2, 5)
//(1)创建并初始赋值可变数组
val arr01 = ArrayBuffer[Any](1, 2, 3)
//(2)遍历数组
for (i <- arr01)
println(i)
println(arr01.length) // 3
println("arr01.hash=" + arr01.hashCode())
//(3)增加元素
//(3.1)追加数据
arr01.+=(4)
arr01.foreach(print(_ ))
println()
//(3.2)向数组最后追加数据
arr01.append(5,6)//追加 5,6
arr01.foreach(print(_))
//(3.3)向指定的位置插入数据
arr01.insert(0,7,8) //第0个位置 插入 7,8
arr01.foreach(print(_))
println()
println("arr01.hash=" + arr01.hashCode())
//(4)修改元素
arr01(1) = 9 //修改第 2 个元素的值
println("--------------------------")
for (i <- arr01)
println(i)
println(arr01.length) // 5
(
1
)
ArrayBuffer
是有序的集合
(
2
)增加元素使用的是
append
方法
()
,支持可变参数
不可变数组与可变数组的转换
arr1.toBuffer //不可变数组转可变数组
arr2.toArray //可变数组转不可变数组
(1)arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化
(2)arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化
多维数组
val arr = Array.ofDim[Double](3,4)
说明:二维数组中有三个一维数组,每个一维数组中有四个元素
object DimArray
def main(args: Array[String]): Unit =
//(1)创建了一个二维数组, 有三个元素,每个元素是,含有 4 个元素一维
数组()
val arr = Array.ofDim[Int](3, 4)
arr(1)(2) = 88
//(2)遍历二维数组
for (i <- arr) //i 就是一维数组
for (j <- i)
print(j + " ")
println()
List
( 1 ) List 默认为不可变集合 ( 2 )创建一个 List (数据有顺序,可重复) ( 3 )遍历 List ( 4 ) List 增加数据 ( 5 )集合间合并:将一个整体拆成一个一个的个体,称为扁平化 ( 6 )取指定数据 ( 7 )空集合 Nilobject TestList
def main(args: Array[String]): Unit =
//(1)List 默认为不可变集合
//(2)创建一个 List(数据有顺序,可重复)
val list: List[Int] = List(1,2,3,4,3)
//(7)空集合 Nil
val list5 = 1::2::3::4::Nil
//(4)List 增加数据
//(4.1)::的运算规则从右向左
//val list1 = 5::list
val list1 = 7::6::5::list
//(4.2)添加到第一个元素位置
val list2 = list.+:(5)
//(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
val list3 = List(8,9)
//val list4 = list3::list1
val list4 = list3:::list1
//(6)取指定数据
println(list(0))
//(3)遍历 List
//list.foreach(println)
//list1.foreach(println)
//list3.foreach(println)
//list4.foreach(println)
list5.foreach(println)
list运算符
package test
/**
* scala中的:: , +:, :+, :::, +++, 等操作;
*/
object listTest
def main(args: Array[String]): Unit =
val list = List(1,2,3)
// :: 用于的是向队列的头部追加数据,产生新的列表, x::list,x就会添加到list的头部
println(4 :: list) //输出: List(4, 1, 2, 3)
// .:: 这个是list的一个方法;作用和上面的一样,把元素添加到头部位置; list.::(x);
println( list.:: (5)) //输出: List(5, 1, 2, 3)
// :+ 用于在list尾部追加元素; list :+ x;
println(list :+ 6) //输出: List(1, 2, 3, 6)
// +: 用于在list的头部添加元素;
val list2 = "A"+:"B"+:Nil //Nil Nil是一个空的List,定义为List[Nothing]
println(list2) //输出: List(A, B)
// ::: 用于连接两个List类型的集合 list ::: list2
println(list ::: list2) //输出: List(1, 2, 3, A, B)
// ++ 用于连接两个集合,list ++ list2
println(list ++ list2) //输出: List(1, 2, 3, A, B)
可变 ListBuffer
( 1 )创建一个可变集合 ListBuffer ( 2 )向集合中添加数据 ( 3 )打印集合数据import scala.collection.mutable.ListBuffer
object TestList
def main(args: Array[String]): Unit =
//(1)创建一个可变集合
val buffer = ListBuffer(1,2,3,4)
//(2)向集合中添加数据
buffer.+=(5)
buffer.append(6)
buffer.insert(1,2)
//(3)打印集合数据
buffer.foreach(println)
//(4)修改数据
buffer(1) = 6
buffer.update(1,7)
//(5)删除数据
buffer.-(5)
buffer.-=(5)
buffer.remove(5)
Set 集合
不可变 Set
object TestSet
def main(args: Array[String]): Unit =
//(1)Set 默认是不可变集合,数据无序
val set = Set(1,2,3,4,5,6)
//(2)数据不可重复
val set1 = Set(1,2,3,4,5,6,3)
//(3)遍历集合
for(x<-set1)
println(x)
可变 mutable.Set
object TestSet
def main(args: Array[String]): Unit =
//(1)创建可变集合
val set = mutable.Set(1,2,3,4,5,6)
//(3)集合添加元素
set += 8
//(4)向集合中添加元素,返回一个新的 Set
val ints = set.+(9)
println(ints)
println("set2=" + set)
//(5)删除数据
set-=(5)
//(2)打印集合
set.foreach(println)
println(set.mkString(","))
Map 集合
Scala 中的 Map 和 Java 类似, 也是一个散列表 ,它存储的内容也是键值对( key-value ) 映射object TestMap
def main(args: Array[String]): Unit =
// Map
//(1)创建不可变集合 Map
val map = Map( "a"->1, "b"->2, "c"->3 )
//(3)访问数据
for (elem <- map.keys)
// 使用 get 访问 map 集合的数据,会返回特殊类型 Option(选项):
有值(Some),无值(None)
println(elem + "=" + map.get(elem).get)
//(4)如果 key 不存在,返回 0
println(map.get("d").getOrElse(0))
println(map.getOrElse("d", 0))
//(2)循环打印
map.foreach((kv)=>println(kv))
可变 Map
object TestSet
def main(args: Array[String]): Unit =
//(1)创建可变集合
val map = mutable.Map( "a"->1, "b"->2, "c"->3 )
//(3)向集合增加数据
map.+=("d"->4)
// 将数值 4 添加到集合,并把集合中原值 1 返回
val maybeInt: Option[Int] = map.put("a", 4)
println(maybeInt.getOrElse(0))
//(4)删除数据
map.-=("b", "c")
//(5)修改数据
map.update("d",5)
map("d") = 5
//(2)打印集合
map.foreach((kv)=>println(kv))
元组
元组可理解为一个容器,存放各种相同或不同类型的数据。 将多个无关的数据封装为一个整体,称为 元组。 注意:元组中最大只能有 22 个元素。object TestTuple
def main(args: Array[String]): Unit =
//(1)声明元组的方式:(元素 1,元素 2,元素 3)
val tuple: (Int, String, Boolean) = (40,"bobo",true)
//(2)访问元组
//(2.1)通过元素的顺序进行访问,调用方式:_顺序号
println(tuple._1)
println(tuple._2)
println(tuple._3)
//(2.2)通过索引访问数据
println(tuple.productElement(0))
//(2.3)通过迭代器访问数据
for (elem <- tuple.productIterator)
println(elem)
//(3)Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为
对偶
val map = Map("a"->1, "b"->2, "c"->3)
val map1 = Map(("a",1), ("b",2), ("c",3))
map.foreach(tuple=>println(tuple._1 + "=" + tuple._2))
操作
通用操作
object TestList
def main(args: Array[String]): Unit =
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
//(1)获取集合长度
println(list.length)
//(2)获取集合大小,等同于 length
println(list.size)
//(3)循环遍历
list.foreach(println)
//(4)迭代器
for (elem <- list.itera tor)
println(elem)
while (iter.hasNext)
println(iter.next())
//(5)生成字符串
println(list.mkString(","))
//(6)是否包含
println(list.contains(3)) //如果存在返回true,不存在返回false
衍生集合操作
object TestList
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)获取集合的头
//获取集合的头使用head方法,可迭代的类型都可以用,一般在有序的类型里面有,无序的不考虑头和尾
println(list1.head) //1
//(2)获取集合的尾(不是头的就是尾)
println(list1.tail) //List(2, 3, 4, 5, 6, 7)
//(3)集合最后一个数据
println(list1.last) //7
//(4)集合初始数据(不包含最后一个)
println(list1.init) //List(1, 2, 3, 4, 5, 6)
//(5)反转
println(list1.reverse)
//(6)取前(后)n 个元素
println(list1.take(3))
println(list1.takeRight(3))
//(7)去掉前(后)n 个元素
println(list1.drop(3))
println(list1.dropRight(3))
//两个集合的操作
//(8)并集
println(list1.union(list2))
println(list1 ::: list2)
/如果是set做并集。那么重复的数据会被去重
val set = Set(6,12,33,45,56)
val set2 = Set(32,65,45,46,321,6)
val union2 = set.union(set2)
println(union2)
println(set ++ set2)
//(9)交集
println(list1.intersect(list2))
//(10)差集
println(list1.diff(list2))
//(11)拉链 注:如果两个集合的元素个数不相等,那么会将同等数量的数据进行拉链,多余的数据省略不用
println(list1.zip(list2))
// (12) 滑窗
//滑窗的意思是,第一次取123元素,第二次去234,每次取三个这样滑下去,每次取多少可以定义
println(list.sliding(3)) //滑窗使用sliding方法,里面的参数是每次滑的元素是几个,可以看到是一个迭代器
for(i <- list.sliding(3)) //使用类似于迭代器的方式遍历出来
println(i)
println("================")
//要是里面有两个参数的话,第二个参数是步长,一个参数的时候默认步长是1
for(i <- list.sliding(3,2))
println(i)
计算函数
object TestList
def main(args: Array[String]): Unit =
val list: List[Int] = List(1, 5, -3, 4, 2, -7, 6)
//(1)求和
println(list.sum)
//(2)求乘积
println(list.product)
//(3)最大值
println(list.max)
//(4)最小值
println(list.min)
排序
sorted
对一个集合进行自然排序,通过传递隐式的 Orderingprintln(list.sorted) //这是升序,从小到大
println(list.sorted.reverse) //降序可以先排序然后翻转列表,可以达到效果
println(list.sorted(Ordered[Int])) //降序
sortBy
对一个属性或多个属性进行排序,通过它的类型。println(list.sortBy(x => x)) //按照元素大小排序
println(list.sortBy(x => x.abs)) //按照元素的绝对值大小排序
sortWith
基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。println(list.sortWith((x, y) => x < y)) //按元素大小升序排序
println(list.sortWith((x, y) => x > y)) //按元素大小降序排序
计算高级函数
(1) 过滤
遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
(2) 转换/映射(map)
将集合中的每一个元素映射到某一个函数
(3) 扁平化 (flatten)
有点像两个列表要合并,列表里面还套着列表,我们要将他打散,这样的操作就叫做扁平化
(4) 扁平化+映射 注:flatMap相当于先进行map操作,再进行flatten操作集合中的每个元素的子元素映射到某个函数并返回新的集合
就是将多个集合展开,组合成新的一个集合。
(5) 分组(group)
按照指定的规则对集合的元素进行分组,分组是转换成了map
(6) 简化(reduce归约)
通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最
终获取结果。(7) 折叠(fold)
object TestList
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))
val wordList: List[String] = List("hello world", "hello atguigu", "hello scala")
//(1)过滤
println(list.filter(x => x % 2 == 0))
//(2)转化/映射
println(list.map(x => x + 1))
//(3)扁平化
println(nestedList.flatten)
//(4)扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten操作
println(wordList.flatMap(x => x.split(" ")))
//(5)分组
println(list.groupBy(x => x % 2))
//reduce
object TestReduce
def main(args: Array[String]): Unit =
val list = List(1,2,3,4)
// 将数据两两结合,实现运算规则
val i: Int = list.reduce( (x,y) => x-y )
println("i = " + i)
// 从源码的角度,reduce 底层调用的其实就是 reduceLeft
//val i1 = list.reduceLeft((x,y) => x-y)
// ((4-3)-2-1) = -2
val i2 = list.reduceRight((x,y) => x-y)
println(i2)
//Fold
list(1,2,3,4)
//10+1+2+3+4
println(list.fold(10)(_+_))
//10-1-2-3-4
list.foldLeft(10)(_-_)
//1-(2-(3-(4-10)))
list.foldRight(10)(_-_)
实例
map1++map2 如果有相同的key,map1的value会被map2的value覆盖
object TestFold
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)
//fold 要求两个()()里 的变量相同
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)
WordCount 案例
单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果package com.qihang.bigdata.spark.core
class Person()
object Test
def main(args: Array[String]): Unit =
//数据
val stringList:List[String]=List(
"hello",
"hello world",
"hello scala",
"hello spark from scala",
"hello flink from scala"
)
//对字符串切分,打散所有单词的列表
// val wordList1 = stringList.map(_.split(" "))
// val wordList2 = wordList1.flatten
val wordList = stringList.flatMap(_.split(" "))
println(wordList) //List(hello, hello, world, hello, scala, hello, spark, from, scala, hello, flink, from, scala)
val groupMap = wordList.groupBy(word => word)
println(groupMap) //Map(world -> List(world), flink -> List(flink), spark -> List(spark), scala -> List(scala, scala, scala), from -> List(from, from), hello -> List(hello, hello, hello, hello, hello))
//对分组之后的list去长度,当成value
val countMap : Map[String,Int]= groupMap.map(kv => (kv._1, kv._2.length))
//排序,需要转化为list,进行排序,取前三
val sortList:List[(String,Int)]=countMap.toList
.sortWith( _._2 > _._2)
.take(3)
println(sortList)
复杂案例
package com.qihang.bigdata.spark.core
class Person()
object Test
def main(args: Array[String]): Unit =
//数据
val stringList:List[(String,Int)]=List(
("hello",1),
("hello world",2),
("hello scala",3),
("hello spark from scala",1),
("hello flink from scala",2)
)
//思路1:打散,变成上一个案例
val newStringList:List[String]=stringList.map(
kv=>
(kv._1.trim + " ")*kv._2
)
val wordCountList:List[(String,Int)]=newStringList
.flatMap(_.split(" "))
.groupBy(word=>word)
.map(kv=>(kv._1,kv._2.length))
.toList
.sortBy(_._2)(Ordering[Int].reverse) //降序排序
.take(3)
//2 基于预处理直接进行处理
//将字符串打散,并和个数包装成二元组
val preCountList:List[(String,Int)] = stringList.flatMap(
tuple =>
val strings:Array[String]=tuple._1.split(" ")
strings.map( word => (word, tuple._2) )
)
println(preCountList)
//List((hello,1), (hello,2), (world,2), (hello,3), (scala,3), (hello,1), (spark,1), (from,1), (scala,1), (hello,2), (flink,2), (from,2), (scala,2))
//对二元组进行分组
val perCountMap:Map[String,List[(String,Int)]] = preCountList.groupBy( _._1 )
println(perCountMap)
//Map(world -> List((world,2)), flink -> List((flink,2)), spark -> List((spark,1)), scala -> List((scala,3), (scala,1), (scala,2)), from -> List((from,1), (from,2)), hello -> List((hello,1), (hello,2), (hello,3), (hello,1), (hello,2)))
//叠加每个单词预统计的个数值
//mapValues 将原有的元素集转换成新的元素集
val countMap = perCountMap.mapValues(
tupleList => tupleList.map(_._2).sum
)
println(countMap)
//Map(world -> 2, flink -> 2, spark -> 1, scala -> 6, from -> 3, hello -> 9)
//转List 排序取前三
val countList = countMap.toList //List((world,2), (flink,2), (spark,1), (scala,6), (from,3), (hello,9))
.sortWith( _._2 > _._2 )
.take(3)
println(countList)
队列
进队和出队的方法分别为 enqueue 和 dequeue 。object TestQueue
def main(args: Array[String]): Unit =
val que = new mutable.Queue[String]()
que.enqueue("a", "b", "c")
println(que.dequeue())
println(que.dequeue())
println(que.dequeue())
并行集合
在集合和函数之间.parval result1 = (0 to 100).mapcase _ =>
Thread.currentThread.getName
val result2 = (0 to 100).par.mapcase _ =>
Thread.currentThread.getName
来源:
尚硅谷
(8条消息) scala中的:: , +:, :+, :::, +++, 等操作的含义_scala:::_JasonLee实时计算的博客-CSDN博客
(11条消息) Scala 集合常用函数_scala滑窗_气质&末雨的博客-CSDN博客
每天学一点Scala之 高阶函数 flatten_51CTO博客_scala高阶函数
scala集合与数据结构
1、数据结构特点
Scala同时支持可变集合和不可变集合,不可变集合从不可变,可以安全的并发访问。
两个主要的包:
不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable
Scala优先采用不可变集合,对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本。
不可变集合继承层次:
可变集合继承层次:
2、数组
2.1、定义定长数组
我们可以定义一个固定长度大小和类型的定长数组
//定义一个数组长度为10,类型为Int的固定大小数组 val array = new Array[Int](10) array(1) = 10 array(2) = 20 //访问数组当中的某一个下标元素值 println(array(1)) //直接使用apply方法进行生成一个数组 val array2 = Array(1,2,3) //访问数组的元素 println(array2(2)) |
|
2.2、变长数组
我们也可以通过ArrayBuffer来定义一个变长数组
val array3 = new ArrayBuffer[Int]() array3.append(20) val array4 = ArrayBuffer[String]() array4.append("helloworld") |
2.3、定长数组与变长数组的相互转换
//定长数组转换成变长数组 val toBuffer = array.toBuffer toBuffer.append(50) //变长数组准换成定长数组 val toArray = array3.toArray |
2.4、多维数组
我们可以通过Array的ofDim方法来定义一个多维的数组,多少行,多少列,都是我们自己定义说了算
val dim = Array.ofDim[Double](3,4) dim(1)(1) = 11.11 println(dim.mkString(",")) |
2.5、scala当中数组的遍历
val array5 = ArrayBuffer(1,2,3,4,5,6) for(x <- array5){ println(x ) } |
2.6、数组的常见算法
val array6 = Array(1,2,3,4,5,6) //求和 array6.sum //求最大值 array6.max //排序 array6.sorted |
3、元组tuple
在scala当中提供元组tuple的数据类型,可以理解tuple为一个容器,可以存放各种不同的数据类型的数据,例如一个Tuple当中既可以存放String类型数据,同时也可以存放Int类型的数据
注意:注意元组一旦创建之后,就是不可变的,也就是说元组当中没有添加和删除元素这一说
3.1、创建元组
创建元组,直接使用小括号,小括号当中存放我们元组当中各种类型的元素即可
val tuple1 = ("hello",1,5.0f) println(tuple1) |
3.2、元组数据的访问
访问元组当中的数据直接使用_加角标即可,但是要注意,元组当中的数据角标是从1开始的
val tuple1 = ("hello",1,5.0f) println(tuple1)
val tuple1Result = tuple1._1 println(tuple1Result) |
3.3、元组的遍历
val tuple1 = ("hello",1,5.0f) println(tuple1)
val tuple1Result = tuple1._1 println(tuple1Result) |
//第一种方式遍历元组
for(x <- tuple1.productIterator){ println(x) } //第二种方式遍历元组 tuple1.productIterator.foreach( x => println(x)) |
4、映射Map
scala当中的Map集合与java当中的Map类似,也是key,value对形式的
4.1、不可变映射
val map1 = Map("hello" ->"world","name" -> "zhangsan","age" -> 18) |
4.2、可变映射及其操作
val map2 = scala.collection.mutable.Map("hello" ->"world","name" -> "zhangsan","age" -> 18) //可变map添加元素 map2.+=("address" ->"地球") println(map2) //可变map删除元素.注意,删除元素是返回一个删除元素之后的map,原来的map并没有改变 val map3 = map2.-("address") println(map2) println(map3)
//可变map更新元素 map2("address") ="火星" println(map2) //或者使用覆盖key的方式来更细元素 map2 += ("address" -> "北京") println(map2) //或者使用 + 来进行更新元素 //注意,map当中没有phonNo这个key,则不能更细 map2 +("address" ->"上海","phonNo" -> "13688886666") println(map2) |
4.3、获取map当中指定的key值
//通过key来进行取值 map2.get("address") //通过key来进行取值,如果没有这个key,就用后面给定的默认值 map2.getOrElse("address","非洲") //通过key来进行取值,真的没有这个key,那么就用后面给定的默认值 map2.getOrElse("phoNo","13133335555") |
4.4、遍历Map当中的元素
//遍历key与value for((k,v) <- map2){ println(k) println(v) }
//遍历获取所有的key for(k <- map2.keys) { println(k) } //遍历获取所有的value for(v <- map2.values) { println(v) }
//打印key,value对 for(kv <- map2){ println(kv) } |
4.5、将对偶的数组转变为map
//将对偶的元组转变为map val arrayMap = Array(("name","zhangsan"),("age",28)) val toMap = arrayMap.toMap println(toMap) |
5、列表(List)
scala当中也提供有与java类似的List集合操作
5.1、创建列表
注意:列表当中的元素类型可以是不同的,这一点与我们元组类似,但是列表当中的元素是可以删减的
val list1 = List("hello",20,5.0f) println(list1) |
5.2、访问列表当中的元素
//访问列表当中的元素 val list1Result = list1(0) println(list1Result) |
5.3、列表当中添加元素
我们可以从列表头部或者尾部添加元素
val list2 = list1:+50 val list3 = 100+:list1 println(list2) println(list3) |
5.4、List的创建与追加元素
Nil是一个空的List,定义为List[Nothing]
//尾部添加了Nil,那么就会出现List集合里面装List集合的现象 val list4 = 1::2 ::3 :: list1 ::Nil println(list4) //尾部没有添加Nil的值,那么所有的元素都压平到一个集合里面去了 val list5 = 1::2::3::list1 println(list5) |
5.5、变长List的创建与使用
val list6 = new ListBuffer[String] list6.append("hello") list6.append("world") println(list6.mkString(",")) val list7 = list6.toList println(list7) |
5.6、List操作延伸阅读
Scala是函数式风格与面向对象共存的编程语言,方法不应该有副作用是函数风格编程的一个重要的理念。方法唯一的效果应该是计算并返回值,用这种方式工作的好处就是方法之间很少纠缠在一起,因此就更加可靠和可重用。另一个好处(静态类型语言)是传入传出方法的所有东西都被类型检查器检查,因此逻辑错误会更有可能把自己表现为类型错误。把这个函数式编程的哲学应用到对象世界里以为着使对象不可变。
前面一章介绍的Array数组是一个所有对象都共享相同类型的可变序列。比方说Array[String]仅包含String。尽管实例化之后你无法改变Array的长度。因此,Array是可变的对象。
说到共享相同类型的不可变对象类型,Scala的List类才是。和数组一样,List[String]包含的仅仅是String。Scala的List不同于Java的java.util.List,总是不可变的(Java的List是可变)。更准确的说法,Scala的List是设计给函数式风格的编程用的。
(1)List类型定义以及List的特点:
//字符串类型List scala> val fruit=List("Apple","Banana","Orange") fruit: List[String] = List(Apple, Banana, Orange) //前一个语句与下面语句等同 scala> val fruit=List.apply("Apple","Banana","Orange") fruit: List[String] = List(Apple, Banana, Orange) //数值类型List scala> val nums=List(1,2,3,4,5) nums: List[Int] = List(1, 2, 3, 4, 5) //多重List,List的子元素为List scala> val list = List(List(1, 2, 3), List("adfa", "asdfa", "asdf")) list: List[List[Any]] = List(List(1, 2, 3), List(adfa, asdfa, asdf))
//遍历List scala> for(i <- list; from=i; j<-from)println(j) 1 2 3 adfa asdfa asdf |
(2)List与Array的区别:
1、List一旦创建,已有元素的值不能改变,可以使用添加元素或删除元素生成一个新的集合返回。
如前面的nums,改变其值的话,编译器就会报错。而Array就可以成功
scala>nums(3)=4 <console>:10: error: value update is not a member of List[Int] nums(3)=4 ^ |
2、List具有递归结构(Recursive Structure),例如链表结构
List类型和气他类型集合一样,它具有协变性(Covariant),即对于类型S和T,如果S是T的子类型,则List[S]也是List[T]的子类型。
例如:
scala>var listStr:List[Object] = List("This", "Is", "Covariant", "Example") listStr:List[Object] = List(This, Is, Covariant, Example)
//空的List,其类行为Nothing,Nothing在Scala的继承层次中的最底层 //,即Nothing是任何Scala其它类型如String,Object等的子类 scala> var listStr = List() listStr:List[Nothing] = List()
scala>var listStr:List[String] = List() listStr:List[String] = List() |
(3)List常用构造方法
//1、常用::及Nil进行列表构建 scala> val nums = 1 :: (2:: (3:: (4 :: Nil))) nums: List[Int] = List(1, 2, 3, 4) //由于::操作符的优先级是从右向左的,因此上一条语句等同于下面这条语句 scala> val nums = 1::2::3::4::Nil nums:List[Int] = List(1, 2, 3, 4) |
至于::操作符的使用将在下面介绍
(4)List常用操作
//判断是否为空 scala> nums.isEmpty res5: Boolean = false //取第一个元素 scala> nums.head res6: Int = 1 //取列表第二个元素 scala>nums.tail.head res7: Int = 2
//取第三个元素 scala>nums.tail.tail.head res8: Int = 3
//插入操作 //在第二个位置插入一个元素 scala>nums.head::(3::nums.tail) res11: List[Int] = List(1, 3, 2, 3, 4)
scala> nums.head::(nums.tail.head::(4::nums.tail.tail)) res12: List[Int] = List(1, 2, 4, 3, 4)
//插入排序算法实现 def isort(xs: List[Int]):List[Int] = { if(xs.isEmpty) Nil else insert(xs.head, issort(xs.tail)) }
def insert(x:Int, xs:List[Int]):List[Int] = { if(xs.isEmpty || x <= xs.head) x::xs else xs.head :: insert(x, xs.tail) }
//连接操作 scala>List(1, 2, 3):::List(4, 5, 6) res13: List[Int] = List(1, 2, 3, 4, 5, 6)
//去除最后一个元素外的元素,返回的是列表 scala> nums.init res13: List[Int] = List(1, 2, 3)
//取出列表最后一个元素 scala>nums.last res14: Int = 4
//列表元素倒置 scala> nums.reverse res15: List[Int] = List(4, 3, 2, 1) //一些好玩的方法调用 scala> nums.reverse.reverse == nums //丢弃前面n个元素 scala>nums drop 3 res16: List[Int] = List(4) //获取前面n个元素 scala>nums take 1 res17: List[Int] = List[1] //将列表进行分割 scala> nums.splitAt(2) res18: (List[Int], List[Int]) = (List(1, 2),List(3, 4)) //前一个操作与下列语句等同 scala> (nums.take(2),nums.drop(2)) res19: (List[Int], List[Int]) = (List(1, 2),List(3, 4)) //Zip操作 scala> val nums=List(1,2,3,4) nums: List[Int] = List(1, 2, 3, 4) scala> val chars=List(‘1‘,‘2‘,‘3‘,‘4‘) chars: List[Char] = List(1, 2, 3, 4) //返回的是List类型的元组(Tuple),返回的元素个数与最小的List集合的元素个数一样 scala> nums zip chars res20: List[(Int, Char)] = List((1,1), (2,2), (3,3), (4,4))
//List toString方法 scala> nums.toString res21: String = List(1, 2, 3, 4)
//List mkString方法 scala> nums.mkString res22: String = 1234
//转换成数组 scala> nums.toArray res23: Array[Int] = Array(1, 2, 3, 4) |
(5)List伴生对象方法
//apply方法 scala> List.apply(1, 2, 3) res24: List[Int] = List(1, 2, 3) //range方法,构建某一值范围内的List scala> List.range(2, 6) res25: List[Int] = List(2, 3, 4, 5) //步长为2 scala> List.range(2, 6,2) res26: List[Int] = List(2, 4) //步长为-1 scala> List.range(2, 6,-1) res27: List[Int] = List() scala> List.range(6,2 ,-1) res28: List[Int] = List(6, 5, 4, 3) //构建相同元素的List scala> List.make(5, "hey") res29: List[String] = List(hey, hey, hey, hey, hey)
//unzip方法 scala> List.unzip(res20) res30: (List[Int], List[Char]) = (List(1, 2, 3, 4),List(1, 2, 3, 4))
//list.flatten,将列表平滑成第一个无素 scala> val xss =List(List(‘a‘, ‘b‘), List(‘c‘), List(‘d‘, ‘e‘)) xss: List[List[Char]] = List(List(a, b), List(c), List(d, e)) scala> xss.flatten res31: List[Char] = List(a, b, c, d, e)
//列表连接 scala> List.concat(List(‘a‘, ‘b‘), List(‘c‘)) res32: List[Char] = List(a, b, c) |
(6)::和:::操作符介绍
List中常用‘::‘,发音为"cons"。Cons把一个新元素组合到已有元素的最前端,然后返回结果List。
scala> val twoThree = List(2, 3) scala> val oneTwoThree = 1 :: twoThree scala> oneTwoThree oneTwoThree: List[Int] = List(1, 2, 3) |
上面表达式"1::twoThree"中,::是右操作数,列表twoThree的方法。可能会有疑惑。表达式怎么是右边参数的方法,这是Scala语言的一个例外的情况:如果一个方法操作符标注,如a * b,那么方法被左操作数调用,就像a.* (b)--除非方法名以冒号结尾。这种情况下,方法被右操作数调用。
List有个方法叫":::",用于实现叠加两个列表。
scala> val one = List(‘A‘, ‘B‘) val one = List(‘A‘, ‘B‘) scala> val two = List(‘C‘, ‘D‘) scala> one:::two res1: List[Char] = List(A, B, C, D) |
6、Set集合
集是不重复元素的结合。集不保留顺序,默认是以哈希集实现。
如果想要按照已排序的顺序来访问集中的元素,可以使用SortedSet(已排序数据集),已排序的数据集是用红黑树实现的。
默认情况下,Scala 使用的是不可变集合,如果你想使用可变集合,需要引用 scala.collection.mutable.Set 包。
6.1、不可变集合的创建
val set1 =Set("1","1","2","3") println(set1.mkString(",")) |
6.2、可变集合的创建以及添加元素
如果我们引入的集合的包是可变的,那么我们创建的集合就是可变的
import scala.collection.mutable.Set val set2 = Set(1, 2, 3) set2.add(4) set2 += 5 //使用.这个方法添加元素,会返回一个新的集合 val set3 = set2.+(6) println(set2.mkString(",")) println(set3.mkString(" |