接下来记录下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集合的记录,后续完善。
来源:https://www.cnblogs.com/youngchaolin/p/12375032.html