1.多條件過(guò)濾
使用尾遞歸的形式對(duì)給定值和多個(gè) filter 條件來(lái)進(jìn)行過(guò)濾深啤,只要滿足其一仪缸,即可返回 true
尾遞歸條件過(guò)濾 func
def filter(key: String, conditionList: List[String], op: (String, String) => Boolean): Boolean = {
@tailrec
def filterBy(key: String, conditionList: List[String], index: Int, op: (String, String) => Boolean): Boolean = {
if (index >= conditionList.length) false
else if (op(key, conditionList(index))) true
else filterBy(key, conditionList, index + 1, op)
}
filterBy(key, conditionList, 0, op)
}
使用例子
該例子給定一個(gè) String List,然后給定多個(gè)過(guò)濾條件,只要滿足其一,即可返回 true维费。這樣判斷l(xiāng)ist中的元素是否以給定的條件開頭作為過(guò)濾條件果元。
val list = List("ab","abc","abcd")
val conditions = List("ab","ac")
list.map {
r =>
if (filter(r, conditions, (k, c) => k.startsWith(c))) {
Option(r)
} else None
}.filter(_.isDefine).map(_.get)
2.優(yōu)雅的遍歷 Map
當(dāng)我需要對(duì)集合的元素進(jìn)行轉(zhuǎn)換時(shí),自然而然會(huì)使用到map方法犀盟。
當(dāng)我們?cè)趯?duì) tuple 類型的集合或者針對(duì) Map 進(jìn)行map操作時(shí)而晒,通常更傾向于在 map 方法中使用 case 語(yǔ)句,這比直接使用_1與_2更加可讀阅畴。例如:
val languageToCount = Map("Scala" -> 10, "Java" -> 20, "Ruby" -> 5)
languageToCount map { case (_, count) => count + 1 }
然而對(duì)于上述場(chǎng)景倡怎,其實(shí)我們也可以使用collect方法:
languageToCount collect { case (_, count) => count + 1 }
效果完全相同。
給定一個(gè) Map 數(shù)據(jù)
val giveMap = Map("a"->"b","c"->"d","e"->"f","g"->"h","i"->"j")
我們一般最常用的方式如下:
giveMap.foreach {
r =>
println(s"key: ${r._1}, value: ${r._2}")
}
更優(yōu)雅的方式贱枣,使用 case 偏函數(shù)监署。這樣可以直觀的將 key 和 value 寫出來(lái),而不需要像上一個(gè)例子那樣以元祖的方式展現(xiàn)纽哥,更直觀和好懂钠乏。
giveMap.foreach {
case (key,value) =>
println(s"key: $key, value: $value")
}
還有一種不常用的遍歷方式
//However it requires explicit type annotations.
giveMap.map(((k: String, v: String) => {
println(s"key: $key, value: $value")
}).tupled)
綜上,在我們一般 map 或者 foreach Map時(shí)春塌,采用case 偏函數(shù)的方式會(huì)更加優(yōu)雅和直觀晓避,推薦使用。
3.對(duì) Map 轉(zhuǎn)換時(shí)使用 mapValues
給定一個(gè) Map 數(shù)據(jù)如下只壳,其中的 value 為一個(gè)二元元祖俏拱,我們需要將此Map 中Value值中的時(shí)間戳去除掉,代碼如下吼句。
使用 mapValues 對(duì) value 值進(jìn)行處理
val giveMap = Map("a" → (5L, "b"), "c" → (1L, "d"), "e" → (8L, "f"), "g" → (4L, "h"))
//一步搞定
val result: Map[String, String] = giveMap.mapValues(_._2)
4.反轉(zhuǎn)一個(gè)已經(jīng)排好序的 Set
Set 沒有 reverse 方法锅必,因此需要我們自己來(lái)進(jìn)行反轉(zhuǎn)
優(yōu)雅的方式如下
//創(chuàng)建 sortedSet 返回值應(yīng)該從小到達(dá)拍好
val value = SortedSet(1, 2, 3, 5, 4, 8, 7, 2, 9)
//轉(zhuǎn)為Int,并進(jìn)行反轉(zhuǎn)
val result = value.foldLeft(List[Int]())((x, y) => y :: x)
5. Par 并行化集合 transfer
使用
par
后命辖,scala
中的集合遍歷會(huì)并行進(jìn)行况毅,這樣如果在需要并行遍歷和處理的業(yè)務(wù)上就能比較簡(jiǎn)單的使用par
來(lái)解決分蓖,而不需要復(fù)雜的future
的編程模型
def test3(): Unit = {
val costMap = Map("1" -> Task("1", 1), "2" -> Task("2", 2), "3" -> Task("3", 3))
val begin = System.currentTimeMillis()
//在這里進(jìn)行 map 操作之前 加入 par 并行化遍歷
val listOfResults: List[String] = costMap.par.map {
case (x, task) => {
Thread.sleep(task.cost * 1000)
task.name
}
}.toList
println(s"結(jié)果耗時(shí): ${System.currentTimeMillis() - begin}")
listOfResults foreach println
}
我們比對(duì)一下沒有 par 和有 par 操作的結(jié)果耗時(shí)
有 par 結(jié)果耗時(shí): 3081ms
普通遍歷結(jié)果耗時(shí): 6009ms
總結(jié):par 并行化遍歷可以將集合中的元素遍歷并行化尔艇,整體處理時(shí)間由最長(zhǎng)的一個(gè)元素遍歷時(shí)間而決定,比如上例中的最大任務(wù)是睡眠3s么鹤,則最終遍歷時(shí)間就在3s左右终娃。
6. Future
1.阻塞等待一個(gè) Future
阻塞等待一個(gè) Future,Scala 如果要及時(shí)獲取到 Future結(jié)果,變異步為同步時(shí)蒸甜,則采用下面這種方法棠耕。注意 import 相關(guān)包
package com.maple.scala.feature
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.language.postfixOps
/**
* Copyright (c) 2018 XiaoMi Inc. All Rights Reserved.
* Authors: Maple <leihuazhe@xiaomi.com> on 19-2-21 17:23
*/
object FutureAwait {
def main(args: Array[String]): Unit = {
val res = Future {
Thread.sleep(2000)
println("----process message end ----")
"我是結(jié)果"
}
println("future 在執(zhí)行,程序繼續(xù)執(zhí)行")
//核心代碼
val result = Await.result(res,5 second)
println(s"返回結(jié)果 $result")
}
}
2. List[Future[T]] -> Future[List[T]]
如果我們?cè)谶M(jìn)行遍歷操作時(shí)柠新,每一行都返回一個(gè) Future窍荧,這樣我們整個(gè)操作最終會(huì)形成一個(gè) List 的 future 集合,這時(shí)我們需要反轉(zhuǎn)為 Future 的 list恨憎,只存在一個(gè) Future 比較好處理結(jié)果蕊退。
def test1(): Unit = {
val costMap = Map("1" -> Task("1", 1), "2" -> Task("2", 2), "3" -> Task("3", 3))
val begin = System.currentTimeMillis()
val listOfFutures: Seq[Future[String]] = costMap.map {
case (x, task) => {
Future {
Thread.sleep(task.cost * 1000)
task.name
}
}
}.toList
val futureOfList:Future[List[String]] = Future.sequence(listOfFutures)
futureOfList onComplete {
case Success(x) => {
val end = System.currentTimeMillis()
println(s"結(jié)果 $x, 耗時(shí): ${end - begin}")
}
case Failure(ex) => println("Failed !!! " + ex)
}
Thread.sleep(Long.MaxValue)
}
7.符號(hào) @ 的用法 (scala symbol @ meaning)
The effect of the @ operator is to alias the value matched on the left to the name on the right for the match.
@運(yùn)算符的作用是將@后面的值賦值給@前面的這個(gè)對(duì)象郊楣,類似于一種 alias的方法
例如:
def test(): Unit = {
val p = Option(2)
p match {
case x@Some(_) ? println(x) //Some(2)
case None ? println("None")
}
}
上面的運(yùn)算符 x@Some(_)
是將后面的值 Some(_)
賦值給了 x,所以 x 的值為 Some(2)
再比如下面幾個(gè)例子:
def test(): Unit = {
val d@(c@Some(a), Some(b)) = (Some(1), Some(2))
println(s"a: $a, b: $b, c: $c, d: $d")
//值分別為: a: 1, b: 2, c: Some(1), d: (Some(1),Some(2))
(Some(1), Some(2)) match {
case d@(c@Some(a), Some(b)) => {
println(a, b, c, d)
//值分別為: 1,2,Some(1),(Some(1),Some(2))
}
}
for (x@Some(y) <- Seq(None, Some(1))) {
println(x, y)
//值分別為(Some(1),1)
}
val List(x, xs@_*) = List(1, 2, 3)
println(x, xs)
//值分別為:(1,List(2, 3))
}