在使用集合函數(shù)比如map
和filter
街佑。這些函數(shù)會及早的創(chuàng)建中間集合愉棱,也就是說每一步的中間結(jié)果都被存儲在一個臨時列表该贾。而序列給了你另一種選擇琼梆,可以讓你避免創(chuàng)建這些臨時的中間對象性誉。如下一個例子:
val peoples = listOf(Person("Alice",20),Person("Bob",31))
peoples.map(Person::name).filter { it.startsWith("A") }
上面的例子中map
和filter
都會返回一個列表,也就是說鏈?zhǔn)降恼{(diào)用會創(chuàng)建兩個列表茎杂,如果源列表中只有兩個元素错览,這不是什么問題,但如果有一百萬個元素煌往,(鏈?zhǔn)?調(diào)用就會變得十分低效倾哺。
為提高效率,可以把操作變成使用序列刽脖,而不是直接使用集合
peoples.asReversed() <!--把初始集合轉(zhuǎn)換成序列-->
.map ( People::name ) <!--序列支持和集合一樣的API-->
.filter {it.startsWith("A") }
.toList() <!--把結(jié)果序列轉(zhuǎn)換回列表-->
Kotlin惰性集合操作的入口就是Sequence
接口羞海,它的強(qiáng)大之處就在于其操作的實(shí)現(xiàn)方式,序列中元素的求值是惰性的曲管。因此可以使用序列高效地對集合元素執(zhí)行鏈?zhǔn)讲僮魅吹耍恍枰獎?chuàng)建額外的集合來保存過程中產(chǎn)生的中間結(jié)果。
可以調(diào)用擴(kuò)展函數(shù)asSequence
把任意集合轉(zhuǎn)換成序列院水,調(diào)用toList
來做反向的轉(zhuǎn)換
中間和末端操作
序列操作分為兩類:中間和末端腊徙。一次中間操作返回的是另一個序列,這個新序列知道如何變換原始序列中的元素檬某。而一次末端操作返回的是一個結(jié)果
中間操作始終是惰性的撬腾,看看下面這個缺少了末端操作的例子
listOf(1,2,3,4).asSequence()
.map{print("map ($it)");it * it}
.filter { print("filter($it)");it % 2 == 0 }
執(zhí)行以上這段代碼不會在控制臺輸出任何內(nèi)容。這意味著map
和filter
變換被延期了恢恼,它們只有在獲取結(jié)果的時候caihui被應(yīng)用(即末端操作被調(diào)用的時候)
在使用map
和filter
進(jìn)行變換時民傻,先應(yīng)用filter
有助于減少變換的次數(shù)。如果map
在前场斑,每個元素都被變換漓踢。而如果filter
在前,不合適的元素會被盡早地過濾掉且不會發(fā)生變換
創(chuàng)建序列
使用generateSequence
函數(shù)創(chuàng)建序列漏隐,給定序列中的前一個元素彭雾,這個函數(shù)會計(jì)算下一個元素
val naturalNumbers = generateSequence(0){it + 1}
val numberTo100 = naturalNumbers.takeWhile { it <= 100 }
println(numberTo100.sum()) <!--在獲取結(jié)果`sum`時,所有被推遲的操作都被執(zhí)行-->
創(chuàng)建使用父目錄的序列锁保,如果元素的父元素和它的類型相同薯酝,你可能會對它的祖先組成的序列的物質(zhì)感興趣半沽。下面的例子可以查詢文件是否放在隱藏目錄中,通過創(chuàng)建一個其父目錄的序列并檢查每個目錄的屬性來實(shí)現(xiàn)
fun File.isInsideHiddenDirectory() =
generateSequence(this){ it.parentFile}.any{ it.isHidden }
val file = File("/Users/svtk/.HiddenDir/a.txt")
println(file.isInsideHiddenDirectory())