zoukankan      html  css  js  c++  java
  • 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集合的记录,后续完善。

  • 相关阅读:
    SecureCRT:保存输出日志的方法
    中文数字转阿拉伯数字
    XP 安装Oralce 10g 数据库
    SQL语句处理一些修改、新增、删除、修改属性操作(MySql)
    SpringBoot整合Shiro完成认证
    SpringBoot 集成Shiro之使用Redis缓存授权认证信息
    解决Establishing SSL connection without server‘s identity verification is not recommended.
    操作系统的内存笔记
    Shiro的认证与授权
    详解 TCP的三次握手四次挥手
  • 原文地址:https://www.cnblogs.com/youngchaolin/p/12375032.html
Copyright © 2011-2022 走看看