使用Scala的强大api快速加工数据

阅读更多

Scala是一门高级的,非常灵活和强大的函数式编程语言,既支持类型严格,语义明确的面向对象的编程风格,也支持类型多变,写法风骚的函数式编码。

Scala中封装了许多有用强大的api,使我们处理数据更加方便,当然Java8以后也支持了一些函数式编程的写法的语法糖,终于能使雍容的java代码精简不少,有名的开源框架如Spark,Kafka,Filnk也都是使用Scala编写的,感兴趣的朋友可以学习一下。

今天来看一个使用Scala处理集合数据的一个小案例:

先看几条例子数据:
班级id 学校id   英雄id  英雄姓名  英雄年龄
c1	s1	1001	张飞	35
c2	s3	1002	高渐离	18
c2	s2	1004	杨戬	25
c2	s4	1005	吕布	36
c3	s1	1006	李白	23


需求就是将如上强势开黑英雄阵容的数据按班级分类,然后每个班级下面可快速通过英雄id(唯一)查询到该英雄,其实思路很明确,只要加工成一个2级map的结构即可,如下:
Map[String,Map[String,Hero]]=Map[班级id,[英雄id,英雄信息]]


我们先看下,造的数据源的几行代码:



  //定义一个case类    
  /***
    * 
    * @param classId 班级id
    * @param schoolId 学校id
    * @param heroId 英雄id
    * @param heroName 英雄名称
    * @param age 年龄
    */
  case class Hero(classId:String,schoolId:String,heroId:String,heroName:String,age:Int){
    override def toString:
    String =
      classId+
      "\t"+schoolId+
      "\t"+heroId+
      "\t"+heroName+
      "\t"+age
  }


    //构建5个英雄的数据
    val s1=Hero("c1","s1","1001","张飞",35)
    val s2=Hero("c2","s3","1002","高渐离",18)
    val s3=Hero("c2","s2","1004","杨戬",25)
    val s4=Hero("c2","s4","1005","吕布",36)
    val s5=Hero("c3","s1","1006","李白",23)

    //将如上强势开黑英雄阵容的数据按班级分类,然后每个班级下面可快速通过英雄id查询到该英雄
    val array=Array(s1,s2,s3,s4,s5)



上面的代码首先定义了一个case类,并重写了其tostring方法,紧接着又构建了一套开黑阵容的英雄的数据,最终将其放在一个数组中,下面看下核心的处理方法:


`   //定义一个存储最终结果的Map结构
    var search_map:Map[String,Map[String,Hero]]=Map()
    //先按班级id分组,并将数据转化成Map结构
    val map:Map[String,Array[Hero]]=array.groupBy(_.classId)
    //再将数据最终的存储结果即可
    map.foreach(kv=>{
      search_map += ( kv._1 -> kv._2.map(hero=>hero.heroId->hero).toMap )
    })


上面的代码就是加工的核心代码,其实只有后面两行才是最核心的,第一行我们首先定义了一个最终的存储结构,然后接着我们对数组进行分组,得到了一个初步的按班级分组的map结构的数据,但是这个map并不是我们想要的,因为它仅仅了提供了班级的映射的数据,如果我们将获取某个班级下的某个英雄的数据,还得遍历整个班级的数据才能找到,所以我们又在第三步对班级的数据做了一个转化,将其原来是Array[Hero]的数据结构,转成了Map[String,Hero]结构,通过Hash表的数据结果,我们能快速定位某个英雄的数据。

下面分析下第三段代码的意思,第二段代码其实比较容易理解就是对数组元素进行按班级分组,返回的结果就是每一个班级,对应一个班级的集合数据,第三段代码核心是下面的这一句:
( kv._1 -> kv._2.map(hero=>hero.heroId->hero).toMap )


前面的+=是追加数据到map集合里面,后面的代码其实里面隐藏了一个个匿名函数:
hero=>hero.heroId->hero

scala里面的map方法的参数是一个函数,首先我们通过map方法,遍历Array[Hero]里面的每一个英雄的数据,然后通过上面代码的这个匿名函数,将生成一个Iterator[(k,v)]数据结构,最终调用toMap方法,将这个集合数据转化成map即可。

在scala里面Map里面一个集合的元素,表示如下:
(k1->v1)
(k2->v2)
(k3->v3)

所以,下面的代码其实就是最终结果的存储的一个kv对内容:
(   kv._1    ->   kv._2.map(hero=>hero.heroId->hero).toMap   )


最后我们来打印下,结果集的数据:
    search_map.foreach(hero=>{
      println("班级id:"+hero._1+" 班级人数:"+hero._2.size)
      hero._2.values.foreach(h=>println(h))
      println("=================================\n")
    })


输出结果如下:
班级id:c1 班级人数:1
c1	s1	1001	张飞	35
=================================

班级id:c3 班级人数:1
c3	s1	1006	李白	23
=================================

班级id:c2 班级人数:3
c2	s3	1002	高渐离	18
c2	s2	1004	杨戬	25
c2	s4	1005	吕布	36
=================================


看到结果是没问题的,scala里面提供了非常多的这点常见的功能强大的api,这一点搞过spark开发的人应该都有体会,里面关于rdd操作的众多方法都与scala的原生的api非常功能非常类似,用起来非常方便。

有什么问题可以扫码关注微信公众号:我是攻城师(woshigcs),在后台留言咨询。 技术债不能欠,健康债更不能欠, 求道之路,与君同行。 使用Scala的强大api快速加工数据_第1张图片

你可能感兴趣的:(scala)