Scala学习-集合相关操作

接下来记录下scala中集合相关的知识,scala中集合分为可变集合和不可变集合,有Array、List、Set、Map和Tuple。

不可变 可变
数组Array Array ArrayBuffer
列表List List ListBuffer
散列Set immutable.Set mutable.Set
映射Map immutable.Map mutable.Map
元祖 Tuple

为了理解的方便,使用交互式方式REPL来完成。

数组

(1)定义一个定长数组。

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

scala> val a2=new Array[Int](4)
a2: Array[Int] = Array(0, 0, 0, 0)

(2)定义一个变长数组。

scala> val a3=scala.collection.mutable.ArrayBuffer(1,2,3,4)
a3: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)
//1 添加一个元素
scala> a3+=5
res1: a3.type = ArrayBuffer(1, 2, 3, 4, 5)
//2 添加一个元素
scala> a3.append(6)
scala> a3
res3: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6)
//3 添加一个元素
scala> a3:+7
res4: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7)

(3)获取元素,修改元素。

//根据下标获取元素
scala> a1.apply(0)
res0: Int = 4
//可以不写apply
scala> a1(0)
res1: Int = 4
//修改元素
scala> a1(0)=520
//查看,修改成功
scala> a1
res3: Array[Int] = Array(520, 1, 2, 5)

(4)数组的切片或截取操作,截取后的依然是一个数组。

scala> val a4=Array(5,2,3,4,6)
a4: Array[Int] = Array(5, 2, 3, 4, 6)
//返回前两位到一个新的数组
scala> val r1=a4.take(2)
r1: Array[Int] = Array(5, 2)
//返回右边数起前两位到一个数组
scala> val r2=a4.takeRight(2)
r2: Array[Int] = Array(4, 6)
//删除前两位,保存剩余数组
scala> val r3=a4.drop(2)
r3: Array[Int] = Array(3, 4, 6)
//删除右边数起前两位,保存剩余数组
scala> val r4=a4.dropRight(2)
r4: Array[Int] = Array(5, 2, 3)

(5)返回头或者尾元素。

//头元素
scala> val r5=a4.head
r5: Int = 5
//take返回的是数组
scala> val r6=a4.take(1)
r6: Array[Int] = Array(5)
//尾元素
scala> val r7=a4.last
r7: Int = 6

(6)求数组最大值、最小值、和、平均值等。

scala> val a5=Array(10,4,6,8,9,2)
a5: Array[Int] = Array(10, 4, 6, 8, 9, 2)
scala> val r8=a5.min
r8: Int = 2
scala> val r9=a5.max
r9: Int = 10
scala> val r9=a5.sum
r9: Int = 39
scala> val r9=a5.sum/a5.length
r9: Int = 6

(7)循环打印。

//foreach里写一个匿名函数
scala> a5.foreach(x=>println(x))
10
4
6
8
9
2

(8)数组的交集、差集和并集。

scala> val a6=Array(1,2,3)
a6: Array[Int] = Array(1, 2, 3)

scala> val a7=Array(3,4,5)
a7: Array[Int] = Array(3, 4, 5)
//求a6和a7的交集
scala> val r12=a6.intersect(a7)
r12: Array[Int] = Array(3)
//求a6和a7的并集
scala> val r13=a7.union(a6)
r13: Array[Int] = Array(3, 4, 5, 1, 2, 3)
//去重
scala> val r14=r13.distinct
r14: Array[Int] = Array(3, 4, 5, 1, 2)
//求a7和a6的差集,得到a7有而a6没有的元素
scala> val r15=a7.diff(a6)
r15: Array[Int] = Array(4, 5)

(9)数组的过滤,使用filter。

scala> val a8=Array(1,2,3,4,5,6)
a8: Array[Int] = Array(1, 2, 3, 4, 5, 6)
//过滤出数组中大于3的元素,返回一个数组。filter里写一个匿名函数
scala> val r16=a8.filter(x=>x>3)
r16: Array[Int] = Array(4, 5, 6)
//匿名函数完整写法
scala> val r17=a8.filter((x:Int)=>{x>3})
r17: Array[Int] = Array(4, 5, 6)
//由于参数x只在方法体使用了一次,可以使用下划线代替
scala> val r18=a8.filter(_>3)
r18: Array[Int] = Array(4, 5, 6)
//求出数组中是偶数并且大于4的数
scala> val r19=a8.filter(x=>x%2==0).filter(x=>x>4)
r19: Array[Int] = Array(6)
scala> val r20=a8.filter(x=>x%2==0&&x>4)
r20: Array[Int] = Array(6)

稍微复杂的过滤。

scala> val a9=Array("tom M 23","rose F 17","jim M 35")
a9: Array[String] = Array(tom M 23, rose F 17, jim M 35)
//过滤男性
scala> val r21=a9.filter(x=>x.contains("M"))
r21: Array[String] = Array(tom M 23, jim M 35)
//过滤男性
scala> val r21=a9.filter(x=>x.split(" ")(1).equals("M"))
r21: Array[String] = Array(tom M 23, jim M 35)
//过滤大于18岁的
scala> val r22=a9.filter(x=>x.split(" ")(2).toInt>18)
r22: Array[String] = Array(tom M 23, jim M 35)

(10)exists返回是否存在某个元素,存在就是true,否则false。

scala> val a9=Array("tom M 23","rose F 17","jim M 35")
a9: Array[String] = Array(tom M 23, rose F 17, jim M 35)

scala> val r24=a9.exists(x=>x.split(" ")(2).toInt>40)
r24: Boolean = false

(11)map映射的使用,可以将一个数组映射为另外一个结果。

scala> val a10=Array(1,2,3,4)
a10: Array[Int] = Array(1, 2, 3, 4)
//映射后结果都变为2倍
scala> val r25=a10.map(num=>num*2)
r25: Array[Int] = Array(2, 4, 6, 8)
//结果变成String类型
scala> val r26=a10.map(num=>num.toString)
r26: Array[String] = Array(1, 2, 3, 4)
//只截取上面a9姓名
scala> val r27=a9.map(line=>line.split(" ")(0))
r27: Array[String] = Array(tom, rose, jim)

scala> val r27=a9.map(line=>line.split(" ").head)
r27: Array[String] = Array(tom, rose, jim)
//a9中男性年龄求和
scala> val r28=a9.filter(line=>line.contains("M")).map(line=>line.split(" ").last.toInt).sum
r28: Int = 58

(12)reduce规约方法。

scala> val a11=Array(1,2,3,4)
a11: Array[Int] = Array(1, 2, 3, 4)
/**
 * reduce 规约方法
 * ① a=1 b=2 a+b=3 a变成3
 * ② a=3 b=3 a+b=6 a变成6
 * ③ a=6 b=4 a+b=10
 */
scala> val r29=a11.reduce((a,b)=>a+b)
r29: Int = 10
//同理,可以求阶乘
scala> val r30=a11.reduce((a,b)=>a*b)
r30: Int = 24

scala> val a12=Array(1,2,3,4,5,6)
a12: Array[Int] = Array(1, 2, 3, 4, 5, 6)
//同理,可以求最大值
scala> val r31=a12.reduce((a,b)=>if(a>b) a else b)
r31: Int = 6

(13)sortBy可以用于排序,默认是升序。

scala> val a12=Array(1,2,3,4,5,6)
a12: Array[Int] = Array(1, 2, 3, 4, 5, 6)
//升序
scala> val r32=a12.sortBy(num=>num)
r32: Array[Int] = Array(1, 2, 3, 4, 5, 6)
//降序
scala> val r32=a12.sortBy(num=>num).reverse
r32: Array[Int] = Array(6, 5, 4, 3, 2, 1)
//降序
scala> val r32=a12.sortBy(num=>num*(-1))
r32: Array[Int] = Array(6, 5, 4, 3, 2, 1)
//降序
scala> val r33=a12.sortBy(num=> -num)
r33: Array[Int] = Array(6, 5, 4, 3, 2, 1)

scala> val a13=Array("tom 23","rose 18","jim 40","jary 35")
a13: Array[String] = Array(tom 23, rose 18, jim 40, jary 35)
//按照姓名的字典序升序排列
scala> val r34=a13.sortBy(line=>line.split(" ").head)
r34: Array[String] = Array(jary 35, jim 40, rose 18, tom 23)
//按照年龄的降序排列
scala> val r35=a13.sortBy(line=>line.split(" ").last.toInt).reverse
r35: Array[String] = Array(jim 40, jary 35, tom 23, rose 18)
//获取年龄最大的前三名,求出年龄的平均值
scala> val r36=a13.sortBy(line=>line.split(" ").last.toInt).reverse.take(3).map(line=>line.split(" ").last.toInt).sum/3
r36: Int = 32
//求出年龄最小的前三名,求出年龄平均值
scala> val r37=a13.map(line=>line.split(" ").last.toInt).sortBy(num=>num).take(3)
r37: Array[Int] = Array(18, 23, 35)
scala> val r38=r37.sum/r37.length
r38: Int = 25

(14)mkString方法,将数组元素变成字符串拼接到一起,还可以指定分隔符。

scala> val a14=Array(100,88,22,55)
a14: Array[Int] = Array(100, 88, 22, 55)

scala> val r39=a14.mkString
r39: String = 100882255

scala> val r40=a14.mkString("#")
r40: String = 100#88#22#55

列表

列表中的方法,可以参考上面的数组,上面可以用的在列表中也可以用。此外列表中有一些特有的方法。

(1)创建列表。

//创建定长列表
scala> val l1=List(1,2,3,4)
l1: List[Int] = List(1, 2, 3, 4)
//创建变长列表
scala> val l2=scala.collection.mutable.ListBuffer(1,2,3,4)
l2: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4)
//通过下标取值
scala> l1(0)
res0: Int = 1

scala> l2(0)
res1: Int = 1

(2)数组转列表,列表转数组。

//列表=>数组
scala> val a1=l1.toArray
a1: Array[Int] = Array(1, 2, 3, 4)
//数组=>链表
scala> val l3=a1.toList
l3: List[Int] = List(1, 2, 3, 4)

(3)在定长列表上追加元素,返回一个新的列表。

//头追加
scala> val l4=l1.::(10)
l4: List[Int] = List(10, 1, 2, 3, 4)
//尾追加
scala> val l5=l1.:+(10)
l5: List[Int] = List(1, 2, 3, 4, 10)

散列

散列中的方法,也可以参考上面的数组,此外set的使用中还有一些特殊的写法。

(1)创建散列set。

//定长set
scala> val s1=Set(1,1,2,2,2,2,3,3,3)
s1: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
//变长set
scala> val s2=scala.collection.mutable.Set(1,2,3,3,3,3,4)
s2: scala.collection.mutable.Set[Int] = Set(1, 2, 3, 4)

(2)交集、并集和差集,还有简单的写法。

//交集
scala> val r1=s1.intersect(s2)
r1: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
scala> val r2=s1&s2
r2: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
//并集
scala> val r3=s1.union(s2)
r3: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)
scala> val r4=s1++s2
r4: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)
//差集
scala> val r5=s2.diff(s1)
r5: scala.collection.mutable.Set[Int] = Set(4)
scala> val r6=s2&~s1
r6: scala.collection.mutable.Set[Int] = Set(4)

映射

映射中的方法,也可以参考上面的数组,其他如下。

(1)创建映射。

//定长映射
scala> val m1=Map("messi"->32,"ronald"->35,"herry"->40)
m1: scala.collection.immutable.Map[String,Int] = Map(messi -> 32, ronald -> 35, herry -> 40)
//变长映射
scala> val m2=scala.collection.mutable.Map("messi"->32,"ronald"->35,"herry"->40)
m2: scala.collection.mutable.Map[String,Int] = Map(messi -> 32, herry -> 40, ronald -> 35)
//变长映射可以追加
scala> m2+=("kaka"->41)
res0: m2.type = Map(kaka -> 41, messi -> 32, herry -> 40, ronald -> 35)

(2)根据key,获取value。

//apply获取
scala> m1.apply("messi")
res1: Int = 32
//省略apply获取
scala> m2("kaka")
res3: Int = 41
//映射没有这个key,以上两种方式都会报错
scala> m1("kaka")
java.util.NoSuchElementException: key not found: kaka
  at scala.collection.MapLike$class.default(MapLike.scala:228)
  at scala.collection.AbstractMap.default(Map.scala:59)
  at scala.collection.MapLike$class.apply(MapLike.scala:141)
  at scala.collection.AbstractMap.apply(Map.scala:59)
  ... 33 elided

scala> m1.apply("kaka")
java.util.NoSuchElementException: key not found: kaka
  at scala.collection.MapLike$class.default(MapLike.scala:228)
  at scala.collection.AbstractMap.default(Map.scala:59)
  at scala.collection.MapLike$class.apply(MapLike.scala:141)
  at scala.collection.AbstractMap.apply(Map.scala:59)
  ... 33 elided
//如果key没有不会报错,使用get方法,它返回值类型为Option类型
//Option有两个子类,None和Some
//如果没有值返回None
//如果有值,返回Some(value)
//不报错,返回None
scala> m1.get("kaka")
res5: Option[Int] = None
//返回Some(value)
scala> m1.get("messi")
res6: Option[Int] = Some(32)
//获取some(value)中的value,如果有这个value返回对应value,没有就返回自己写的
scala> m1.get("messi").getOrElse("我不知道")
res7: Any = 32
scala> m1.get("kaka").getOrElse("我不知道")
res8: Any = 我不知道

(3)返回所有的key和value,并存到一个迭代器中。

scala> m1.keys
res9: Iterable[String] = Set(messi, ronald, herry)

scala> m1.values
res10: Iterable[Int] = MapLike(32, 35, 40)

(4)遍历映射。

//方式1
scala> for(x<-m1){
     | println(x)
     | }
(messi,32)
(ronald,35)
(herry,40)
//方式2
scala> for((k,v)<-m1){
     | println((k,v))
     | }
(messi,32)
(ronald,35)
(herry,40)
//方式3
scala> m1.foreach(println)
(messi,32)
(ronald,35)
(herry,40)

(5)针对key-value的操作。

//过滤年龄大于20的
scala> val r1=m1.filter{case(k,v)=>v>20}
r1: scala.collection.immutable.Map[String,Int] = Map(messi -> 32, ronald -> 35, herry -> 40)
//key不变,年龄+1
scala> val r2=m1.map{case(k,v)=>(k,v+1)}
r2: scala.collection.immutable.Map[String,Int] = Map(messi -> 33, ronald -> 36, herry -> 41)
//如果只有value有改动,使用mapValue方法
scala> val r3=m1.mapValues(v=>v+1)
r3: scala.collection.immutable.Map[String,Int] = Map(messi -> 33, ronald -> 36, herry -> 41)

(6)Map可以转换成数组或列表,数组里的元素就是元祖类型。

//to Array
scala> val r4=m1.toArray
r4: Array[(String, Int)] = Array((messi,32), (ronald,35), (herry,40))
//to List
scala> m1.toList
res34: List[(String, Int)] = List((messi,32), (ronald,35), (herry,40))

元祖

元祖很重要,一般在spark处理数据时,很多类型是元祖形式。

(1)创建一个元祖,元祖元素可以是任何类型。

//创建元祖
scala> val t1=(1,2,3,4)
t1: (Int, Int, Int, Int) = (1,2,3,4)
//元祖里是String、Int,数组和列表
scala> val t2=("hello",1234,Array(1,2,3),List(4,5))
t2: (String, Int, Array[Int], List[Int]) = (hello,1234,Array(1, 2, 3),List(4, 5))
//获取元祖中为5的数字,._4获取第四个元祖元素,即列表,然后获取下标为1的数字,就是5
scala> val r1=t2._4(1)
r1: Int = 5
//再创建一个元祖
scala> val t3=((1,2),(Array(3,4),(5,6)))
t3: ((Int, Int), (Array[Int], (Int, Int))) = ((1,2),(Array(3, 4),(5,6)))
//获取元祖中为5的数字
scala> val r2=t3._2._2._1
r2: Int = 5

(2)map中的(key,value)可以看成元祖来处理。

scala> val m1=Map("tom"->23,"rose"->18)
m1: scala.collection.immutable.Map[String,Int] = Map(tom -> 23, rose -> 18)
//判断map中年龄大于20的,map来考虑
scala> m1.filter{case(k,v)=>v>20}
res14: scala.collection.immutable.Map[String,Int] = Map(tom -> 23)
//判断map中年龄大于20的,(key,value)当做元祖来处理,x._2就是value
scala> m1.filter{x=>x._2>20}
res15: scala.collection.immutable.Map[String,Int] = Map(tom -> 23)

(3)元祖的应用。

scala> val l1=List(("tom","M",23),("rose","F",18),("jim","M",30))
//过滤男性,求男性年龄之和
scala> val r3=l1.filter{x=>x._2.equals("M")}.map{x=>x._3.toInt}.sum
r3: Int = 53
l1: List[(String, String, Int)] = List((tom,M,23), (rose,F,18), (jim,M,30))
//得到年龄最大的人的姓名
scala> val r4=l1.sortBy(x=>x._3.toInt).last._1
r4: String = jim
//得到年龄最大的两个人的姓名,将名字拼接起来了
scala> val r5=l1.sortBy(x=>x._3.toInt).takeRight(2).map{x=>x._1}.mkString("|")
r5: String = tom|jim

(4)map和flatMap。

scala> val l2=List("hello world","hello hadoop","hello spark")
l2: List[String] = List(hello world, hello hadoop, hello spark)
//map的效果,没有改变元素个数,只是改变了形式,由String->Array[String]
scala> val r6=l2.map{line=>line.split(" ")}
r6: List[Array[String]] = List(Array(hello, world), Array(hello, hadoop), Array(hello, spark))
//flatmap的效果,改变了元素个数,也改变了形式
scala> val r7=l2.flatMap{line=>line.split(" ")}
r7: List[String] = List(hello, world, hello, hadoop, hello, spark)

(5)groupBy分组。

scala> val l3=List(("bj",1),("sh",1),("bj",3),("sh",4))
l3: List[(String, Int)] = List((bj,1), (sh,1), (bj,3), (sh,4))
//通过名字分组
scala> l3.groupBy(x=>x._1)
res16: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(bj -> List((bj,1), (bj,3)), sh -> List((sh,1), (sh,4)))

(6)元祖应用-单词词频统计,类似mapreduce的reduce。

scala> val l4=List("hello world","hello hadoop","hello hive","hello world")
l4: List[String] = List(hello world, hello hadoop, hello hive, hello world)
//统计上面的词频

//方式1
scala> l4.flatMap{line=>line.split(" ")}.map{word=>(word,1)}.groupBy{x=>x._1}
res38: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(hadoop -> List((hadoop,1)), world -> List((world,1), (world,1)), hive -> List((hive,1)), hello -> List((hello,1), (hello,1), (hello,1), (hello,1)))
//将上面list((string,int),...)->int,提取里面的数字,再求和
scala> l4.flatMap{line=>line.split(" ")}.map{word=>(word,1)}.groupBy{x=>x._1}.mapValues{list=>list.map(x=>x._2).sum} //list是列表,map里的元素x是元祖
res39: scala.collection.immutable.Map[String,Int] = Map(hadoop -> 1, world -> 2, hive -> 1, hello -> 4)
//转成array
scala> l4.flatMap{line=>line.split(" ")}.map{word=>(word,1)}.groupBy{x=>x._1}.mapValues{list=>list.map(x=>x._2).sum}.toArray
res40: Array[(String, Int)] = Array((hadoop,1), (world,2), (hive,1), (hello,4))
//方式2
scala> l4.flatMap{line=>line.split(" ")}.groupBy(word=>word)
res41: scala.collection.immutable.Map[String,List[String]] = Map(hadoop -> List(hadoop), world -> List(world, world), hive -> List(hive), hello -> List(hello, hello, hello, hello))
//统计分组后value的长度
scala> l4.flatMap{line=>line.split(" ")}.groupBy(word=>word).mapValues{list=>list.length}
res42: scala.collection.immutable.Map[String,Int] = Map(hadoop -> 1, world -> 2, hive -> 1, hello -> 4)
//转成array
scala> l4.flatMap{line=>line.split(" ")}.groupBy(word=>word).mapValues{list=>list.length}.toArray
res43: Array[(String, Int)] = Array((hadoop,1), (world,2), (hive,1), (hello,4))
//方式3
scala> l4.flatMap{line=>line.split(" ")}.groupBy(word=>word).map{case(k,v)=>(k,v.length)}
res44: scala.collection.immutable.Map[String,Int] = Map(hadoop -> 1, world -> 2, hive -> 1, hello -> 4)

scala> l4.flatMap{line=>line.split(" ")}.groupBy(word=>word).map{case(k,v)=>(k,v.length)}.toList
res45: List[(String, Int)] = List((hadoop,1), (world,2), (hive,1), (hello,4))

(7)tuple和match配合使用,可以进行匹配。

scala> var arr=Array(("rose",18),("jack",22),("clyang",28),("messi",33,80))
arr: Array[Product with Serializable] = Array((rose,18), (jack,22), (clyang,28), (messi,33,80))
//类似java中的switch-case
scala> for(t<-arr){
     | t match{
     |   case(_,_) => println(t+"是一个二元tuple")
     |   case(_,_,_) => println(t+"是一个三元tuple")
     |  }
     | }
(rose,18)是一个二元tuple
(jack,22)是一个二元tuple
(clyang,28)是一个二元tuple
(messi,33,80)是一个三元tuple
scala> for(t<-arr){
     | t match{
     |   case("rose",_)=>println("rose:"+t)
     |   case("jack",_)=>println("jack:"+t)
     |   case _ => println(t)
     |  }
     | }
rose:(rose,18)
jack:(jack,22)
(clyang,28)
(messi,33,80)

以上,是对scala集合的记录,后续完善。

posted @ 2020-02-27 22:47  斐波那切  阅读(1001)  评论(0编辑  收藏  举报