使用Scala的強大api快速加工數據

Scala是一門高級的,很是靈活和強大的函數式編程語言,既支持類型嚴格,語義明確的面向對象的編程風格,也支持類型多變,寫法風騷的函數式編碼。java

Scala中封裝了許多有用強大的api,使咱們處理數據更加方便,固然Java8之後也支持了一些函數式編程的寫法的語法糖,終於能使雍容的java代碼精簡很多,有名的開源框架如Spark,Kafka,Filnk也都是使用Scala編寫的,感興趣的朋友能夠學習一下。編程

今天來看一個使用Scala處理集合數據的一個小案例:api

先看幾條例子數據:數組

班級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表的數據結果,咱們能快速定位某個英雄的數據。ide

下面分析下第三段代碼的意思,第二段代碼其實比較容易理解就是對數組元素進行按班級分組,返回的結果就是每個班級,對應一個班級的集合數據,第三段代碼核心是下面的這一句:函數式編程

( 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很是功能很是相似,用起來很是方便。

相關文章
相關標籤/搜索