十個驚人的Scala集合操作函數(shù)
當我操作 Scala 集合時惩阶,我一般會進行兩類操作:轉(zhuǎn)換操作(transformation )和行動操作(actions)(有些人喜歡叫他為聚合操作)。第一種操作類型將集合轉(zhuǎn)換為另一個集合,第二種操作類型返回某些類型的值事镣。
本文我將集中介紹幾個日常工作必備的 [Scala(https://www.iteblog.com/archives/tag/scala/) 集合函數(shù),如轉(zhuǎn)換函數(shù)和聚合函數(shù)焊夸。文章最后苛败,我會展示如何結(jié)合這些函數(shù)以解決具體問題。
文章目錄
· 1?最大值和最小值
· 2?Filter
· 4?歐拉圖函數(shù)(Euler Diagram函數(shù))
· 9?Fold
十個驚人的scala集合操作函數(shù)
https://www.iteblog.com/archives/1946.html
最大值和最小值
我們先從動作函數(shù)(
action function)開始镰矿。在序列中查找最大或最小值是一個極常見的需求琐驴,較常用于面試問題和算法。還記得 Java 中的代碼行嗎?如下:
int[] arr = {11, 2, 5, 1, 6, 3, 9};
int to = arr.length - 1;
int max = arr[0];
for (int i = 0; i < to; i++) {
if (max < arr[i+1])
max = arr[i+1];
}
System.out.println(max);
問題:怎么在List 中找到最大/最小值呢绝淡?
Scala 推薦了一個很贊的解決方案:
val numbers = Seq(11, 2, 5, 1, 6, 3, 9)
numbers.max //11
numbers.min //1
但實際操作的數(shù)據(jù)更加復雜宙刘。下面我們介紹一個更高級的例子,其中包含一個書的序列(查看源代碼案例)牢酵。
case class Book(title: String, pages: Int)
val books = Seq(
Book("Future of Scala developers", 85),
Book("Parallel algorithms", 240),
Book("Object Oriented Programming", 130),
Book("Mobile Development", 495)
)
//Book(Mobile Development,495)
books.maxBy(book => book.pages)
//Book(Future of Scala developers,85)
books.minBy(book => book.pages)
如上所示悬包,
minBy & maxBy方法解決了復雜數(shù)據(jù)的問題。你只需選擇決定數(shù)據(jù)最大或最小的屬性馍乙。
Filter
你過濾過集合嗎布近?比如,篩選價格大于10美元的條目丝格,或挑選年齡在24歲以下員工等撑瞧,所有這些操作屬于過濾。
讓我們舉例說明:過濾一個數(shù)字List显蝌,只獲取奇數(shù)的元素预伺。
val numbers = Seq(1,2,3,4,5,6,7,8,9,10)
numbers.filter(n **=**> n **%** 2 **==** 0)
然后加大難度,我想獲取頁數(shù)大于
120頁的書曼尊。
val books = Seq(
Book("Future of Scala developers", 85),
Book("Parallel algorithms", 240),
Book("Object Oriented Programming", 130),
Book("Mobile Development", 495)
)
books.filter(book => book.pages >= 120)
實際上酬诀,過濾是一個轉(zhuǎn)換類型的方法,但是比運用min和max方法簡單骆撇。
還有一個與filter類似的方法是filterNot料滥。它的名字就體現(xiàn)了它的作用。如果你還是不了解它的實際用途艾船,你可以在一個示例中葵腹,用filterNot替換filter 方法。
Flatten
我想大多數(shù)朋友都沒聽說過這個功能屿岂。其實它很好理解践宴,我們來舉例說明:
val abcd = Seq('a', 'b', 'c', 'd')
val efgj = Seq('e', 'f', 'g', 'h')
val ijkl = Seq('i', 'j', 'k', 'l')
val mnop = Seq('m', 'n', 'o', 'p')
val qrst = Seq('q', 'r', 's', 't')
val uvwx = Seq('u', 'v', 'w', 'x')
val yz = Seq('y', 'z')
val alphabet = Seq(abcd, efgj, ijkl, mnop, qrst, uvwx, yz)
// List(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)
alphabet.flatten
當有一個集合的集合,然后你想對這些集合的所有元素進行操作時爷怀,就會用到
flatten阻肩。
歐拉圖函數(shù)(Euler Diagram函數(shù))
不要緊張!接下來的操作大家都熟知:差集运授、交集和并集烤惊。以下示例能很好地解釋
Euler Diagram 函數(shù):
val num1 = Seq(1, 2, 3, 4, 5, 6)
val num2 = Seq(4, 5, 6, 7, 8, 9)
//List(1, 2, 3)
num1.diff(num2)
//List(4, 5, 6)
num1.intersect(num2)
//List(1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9)
num1.union(num2)
上述示例中的 union保留了重復的元素。如果我們不需要重復怎么辦吁朦?這時可以使用
distinct函數(shù):
//List(1, 2, 3, 4, 5, 6, 7, 8, 9)
num1.union(num2).distinct
下面是上述功能的圖示:
map列表元素
map 是 Scala 集合最常用的一個函數(shù)柒室。它的功能十分強大:
val numbers = Seq(1,2,3,4,5,6)
//List(2, 4, 6, 8, 10, 12)
numbers.map(n **=**> n * 2)
val chars = Seq('a', 'b', 'c', 'd')
//List(A, B, C, D)
chars.map(ch **=**> ch.toUpper)
map 函數(shù)的邏輯是遍歷集合中的元素并對每個元素調(diào)用函數(shù)。你也可以不調(diào)用任何函數(shù)逗宜,保持返回元素本身雄右,但這樣 map無法發(fā)揮作用空骚,因為你在映射過后得到的是同樣的集合。
flatMap
我很難具體說明flatMap 的使用場合擂仍,因為很多不同的情況下都會用到 flatMap囤屹。如果大家仔細觀察,就會發(fā)現(xiàn)flatMap 是由下列這兩個函數(shù)組成的:map & flatten
現(xiàn)在逢渔,假設我們想知道字母表中的大寫字母和小寫字母的排列情況:
val abcd = Seq('a', 'b', 'c', 'd')
//List(A, a, B, b, C, c, D, d)
abcd.flatMap(ch **=**> List(ch.toUpper, ch))
因為這篇文章是關于集合功能的介紹肋坚,所以此處略過
Future 和 Option 的示例。
對整個集合進行條件檢查
有一個場景大家都知道肃廓,即確保集合中所有元素都要符合某些要求智厌,如果有哪怕一個元素不符合條件,就需要進行一些處理:
val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2)
//ture
numbers.forall(n **=**> n < 10)
//false
numbers.forall(n **=**> n > 5)
而forall 函數(shù)就是為處理這類需求而創(chuàng)建的亿昏。
對集合進行分組
你是否嘗試過將一個集合按一定的規(guī)則拆分成兩個新的集合?比如档礁,我們把某個集合拆分成偶數(shù)集和奇數(shù)集角钩,partition 函數(shù)可以幫我們做到這一點:
val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2)
//(List(2, 6, 4, 2), List(3, 7, 9, 5, 1))
numbers.partition(n **=**> n **%** 2 **==** 0)
Fold
另一個流行的操作是fold。
在Scala 的上下文中呻澜,通车堇瘢可以考慮 foldLeft 和 foldRight。他們是從不同的方面做同樣的工作:
val numbers = Seq(1, 2, 3, 4, 5)
//15
numbers.foldLeft(0)((res, n) **=**> res + n)
在第一對括號中羹幸,我們放一個起始值脊髓。
在第二對括號中,我們定義需要對數(shù)字序列的每個元素執(zhí)行的操作栅受。
第一步将硝,n = 0,然后它根據(jù)序列元素變化屏镊。
另一個關于foldLeft 的例子依疼,計算字符數(shù):
val words = Seq("apple", "dog", "table")
//13
words.foldLeft(0)((resultLength, word) **=**> resultLength + word.length)
您最喜歡的函數(shù)
經(jīng)過了上面一系列的列舉,從Scala集合找到你最喜歡的函數(shù)是很酷的(cool)而芥。請大家在評論中寫下它律罢,并提供其使用的例子。
最近我通過了一個編譯測試棍丐,任務的內(nèi)容是:給你一個String S误辑,你需要找到包含大寫和小寫字符,但不包含數(shù)字的最長子字符串歌逢。
比如: dP4knqw1QAp
答案: QAp
那么我們?nèi)绾问褂肧cala集合函數(shù)來解決這個問題呢:
def theLongest(s: String): String = {
s.split ("[0-9]")
.filter (_.exists (ch => ch.isUpper))
.filter (_.exists (ch => ch.isLower))
.maxBy (_.length)
}
上面的函數(shù)解決了這個問題巾钉。如果輸入字符串不包含任何合適的子字符串,將會拋出
UnsupportedOperationException秘案。
總結(jié)
Scala具有令人難以置信的強大的集合API睛琳,你可以利用它做很多的事情盒蟆。 此外,相同的事情可以以不同的方式進行师骗,例如: 上面的歐拉函數(shù)例子历等。 Scala的API是很豐富的,我們需要很多時間和練習來學習它辟癌。