欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Kotlin的Collection與Sequence操作異同點(diǎn)詳解

 更新時(shí)間:2022年10月20日 17:24:26   作者:newki  
這篇文章主要介紹了Kotlin的Collection與Sequence操作異同點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

在Android開發(fā)中,集合是我們必備的容器,Kotlin的標(biāo)準(zhǔn)庫(kù)中提供了很多處理集合的方法,而且還提供了兩種基于容器的工作方式:Collection 和 Sequence。

Collection 是我們常見的,而 Sequence 確是我們少見的,甚至很多人都沒有聽說過(是的,說的就是我 ?? ??)

本篇文章就來介紹一下常用的一些集合操作符,以及 Collection 與 Sequence 的區(qū)別,到底怎么用!

Collection 的常見操作

Collection 集合,Kotlin的集合類型和Java不一樣,Kotlin的集合分為可變(讀寫)和不可變(只讀)類型(lists, sets, maps, etc),可變類型是在不可變類型前面加Mutable,以我們常用的三種集合類型為例:

List<out E> - MutableList<E>
Set<out E> - MutableSet<E>
Map<K, out V> - MutableMap<K, V>

其實(shí)他們的區(qū)別就是List實(shí)現(xiàn)了Collection接口,而MutableList實(shí)現(xiàn)的是List和MutableCollection接口。而 MutableCollection 接口實(shí)現(xiàn)了Collection 接口,并且在里面添加了add和remove等操作方法。

可變不可變只是為了區(qū)分只讀和讀寫的操作,他們的操作符方式都是相同的。

集合的操作符說起來可就太多了

累計(jì)

//對(duì)所有元素求和
list.sum()
//將集合中的每一個(gè)元素代入lambda表達(dá)式,然后對(duì)lambda表達(dá)式的返回值求和
list.sumBy {
    it % 2
}
//在一個(gè)初始值的基礎(chǔ)上,從第一項(xiàng)到最后一項(xiàng)通過一個(gè)函數(shù)累計(jì)所有的元素
list.fold(100) { accumulator, element ->
    accumulator + element / 2
}
//同fold,只是迭代的方向相反
list.foldRight(100) { accumulator, element ->
    accumulator + element / 2
}
//同fold,只是accumulator的初始值就是集合的第一個(gè)元素,element從第二個(gè)元素開始
list.reduce { accumulator, element ->
    accumulator + element / 2
}
//同reduce但方向相反:accumulator的初始值就是集合的最后一個(gè)元素,element從倒數(shù)第二個(gè)元素開始往前迭代
list.reduceRight { accumulator, element ->
    accumulator + element / 2
}
val list = listOf(1, 2, 3, 4, 5, 6)
//只要集合中的任何一個(gè)元素滿足條件(使得lambda表達(dá)式返回true),any函數(shù)就返回true
list.any {
    it >= 0
}
//集合中的全部元素都滿足條件(使得lambda表達(dá)式返回true),all函數(shù)才返回true
list.all {
    it >= 0
}
//若集合中沒有元素滿足條件(使lambda表達(dá)式返回true),則none函數(shù)返回true
list.none {
    it < 0
}
//count函數(shù)的返回值為:集合中滿足條件的元素的總數(shù)
list.count {
    it >= 0
}

遍歷

//遍歷所有元素
list.forEach {
    print(it)
}
//同forEach,只是可以同時(shí)拿到元素的索引
list.forEachIndexed { index, value ->
    println("position $index contains a $value")
}
showFields.forEach { (key, value) ->

最大最小

//返回集合中最大的元素,集合為空(empty)則返回null
list.max()
//返回集合中使得lambda表達(dá)式返回值最大的元素,集合為空(empty)則返回null
list.maxBy { it }
//返回集合中最小的元素,集合為空(empty)則返回null
list.min()
//返回集合中使得lambda表達(dá)式返回值最小的元素,集合為空(empty)則返回null
list.minBy { it }

過濾(去除)

//返回一個(gè)新List,去除集合的前n個(gè)元素
list.drop(2)
//返回一個(gè)新List,去除集合的后n個(gè)元素
list.dropLast(2)
//返回一個(gè)新List,去除集合中滿足條件(lambda返回true)的第一個(gè)元素
list.dropWhile {
    it > 3
}
//返回一個(gè)新List,去除集合中滿足條件(lambda返回true)的最后一個(gè)元素
list.dropLastWhile {
    it > 3
}
//返回一個(gè)新List,包含前面的n個(gè)元素
list.take(2)
//返回一個(gè)新List,包含最后的n個(gè)元素
list.takeLast(2)
//返回一個(gè)新List,僅保留集合中滿足條件(lambda返回true)的第一個(gè)元素
list.takeWhile {
    it>3
}
//返回一個(gè)新List,僅保留集合中滿足條件(lambda返回true)的最后一個(gè)元素
list.takeLastWhile {
    it>3
}
//返回一個(gè)新List,僅保留集合中滿足條件(lambda返回true)的元素,其他的都去掉
list.filter {
    it > 3
}
//返回一個(gè)新List,僅保留集合中不滿足條件的元素,其他的都去掉
list.filterNot {
    it > 3
}
//返回一個(gè)新List,僅保留集合中的非空元素
list.filterNotNull()
//返回一個(gè)新List,僅保留指定索引處的元素
list.slice(listOf(0, 1, 2))

映射

//將集合中的每一個(gè)元素代入lambda表達(dá)式,lambda表達(dá)式必須返回一個(gè)元素
//map的返回值是所有l(wèi)ambda表達(dá)式的返回值所組成的新List
//例如下面的代碼和listOf(2,4,6,8,10,12)將產(chǎn)生相同的List
list.map {
    it * 2
}
//將集合中的每一個(gè)元素代入lambda表達(dá)式,lambda表達(dá)式必須返回一個(gè)集合
//而flatMap的返回值是所有l(wèi)ambda表達(dá)式返回的集合中的元素所組成的新List
//例如下面的代碼和listOf(1,2,2,3,3,4,4,5,5,6,6,7)將產(chǎn)生相同的List
list.flatMap {
    listOf(it, it + 1)
}
//和map一樣,只是lambda表達(dá)式的參數(shù)多了一個(gè)index
list.mapIndexed { index, it ->
    index * it
}
//和map一樣,只不過只有l(wèi)ambda表達(dá)式的非空返回值才會(huì)被包含在新List中
list.mapNotNull {
    it * 2
}
//根據(jù)lambda表達(dá)式對(duì)集合元素進(jìn)行分組,返回一個(gè)Map
//lambda表達(dá)式的返回值就是map中元素的key
//例如下面的代碼和mapOf("even" to listOf(2,4,6),"odd" to listOf(1,3,5))將產(chǎn)生相同的map
list.groupBy {
    if (it % 2 == 0) "even" else "odd"
}

元素

list.contains(2)
list.elementAt(0)
//返回指定索引處的元素,若索引越界,則返回null
list.elementAtOrNull(10)
//返回指定索引處的元素,若索引越界,則返回lambda表達(dá)式的返回值
list.elementAtOrElse(10) { index ->
    index * 2
}
//返回list的第一個(gè)元素
list.first()
//返回list中滿足條件的第一個(gè)元素
list.first {
    it > 1
}
//返回list的第一個(gè)元素,list為empty則返回null
list.firstOrNull()
//返回list中滿足條件的第一個(gè)元素,沒有滿足條件的則返回null
list.firstOrNull {
    it > 1
}
list.last()
list.last { it > 1 }
list.lastOrNull()
list.lastOrNull { it > 1 }
//返回元素2第一次出現(xiàn)在list中的索引,若不存在則返回-1
list.indexOf(2)
//返回元素2最后一次出現(xiàn)在list中的索引,若不存在則返回-1
list.lastIndexOf(2)
//返回滿足條件的第一個(gè)元素的索引
list.indexOfFirst {
    it > 2
}
//返回滿足條件的最后一個(gè)元素的索引
list.indexOfLast {
    it > 2
}
//返回滿足條件的唯一元素,如果沒有滿足條件的元素或滿足條件的元素多于一個(gè),則拋出異常
list.single {
    it == 5
}
//返回滿足條件的唯一元素,如果沒有滿足條件的元素或滿足條件的元素多于一個(gè),則返回null
list.singleOrNull {
    it == 5
}

排序&逆序

val list = listOf(1, 2, 3, 4, 5, 6)
//返回一個(gè)顛倒元素順序的新集合
list.reversed()
/**
 * 返回一個(gè)升序排序后的新集合
 */
list.sorted()
//將每個(gè)元素代入lambda表達(dá)式,根據(jù)lambda表達(dá)式返回值的大小來對(duì)集合進(jìn)行排序
list.sortedBy {
    it*2
}
/**
 * 功能和上面一樣 -> 上面是從小到大排列,這個(gè)返回的是從大到小
 */
list.sortedDescending()
list.sortedByDescending {
    it*2
}
/**
 * 根據(jù)多個(gè)條件排序
 * 先根據(jù)age 升序排列,若age相同,根據(jù)name升序排列,但是都是默認(rèn)的升序排列
 */
personList.sortWith(compareBy({ it.age }, { it.name }))
 /**
 * 根據(jù)多個(gè)條件排序,自定義的規(guī)則
 * 構(gòu)造一個(gè)Comparator對(duì)象,完成排序邏輯:先按age降序排列,若age相同,則按name升序排列
 */
val c1: Comparator<Person> = Comparator { o1, o2 -> 
      if (o2.age == o1.age) {   
          o1.name.compareTo(o2.name)
      } else { 
          o2.age - o1.age 
      }
 }
personList.sortWith(c1)
  //上面的自定義方式可以通過JavaBean實(shí)現(xiàn)Comparable 接口實(shí)現(xiàn)自定義的排序
    data class Person(var name: String, var age: Int) : Comparable<Person> {
     override fun compareTo(other: Person): Int {
         if (this.age == other.age) { 
              return this.name.compareTo(other.name) 
         } else {
             return other.age - this.age 
         } 
     }
   }
 //sorted 方法返回排序好的list(已有有排序規(guī)則的用sorted,不要用sortedby了)
 val sorted = personList.sorted()

Sequence 的常見操作

Sequence 是 Kotlin 中一個(gè)新的概念,用來表示一個(gè)延遲計(jì)算的集合。Sequence 只存儲(chǔ)操作過程,并不處理任何元素,直到遇到終端操作符才開始處理元素,我們也可以通過 asSequence 擴(kuò)展函數(shù),將現(xiàn)有的集合轉(zhuǎn)換為 Sequence ,代碼如下所示

    val list = mutableListOf<Person>()
    for (i in 1..10000) {
        list.add(Person("name$i", (0..100).random()))
    }
    list.asSequence()

當(dāng)我們拿到結(jié)果之后我們還能通過toList再轉(zhuǎn)換為集合。

  list.asSequence().toList()

Sequence的操作符絕大部分都是和 Collection 類似的。常用的一些操作符是可以直接平替使用的。

  val list2 = list.asSequence()
    .filter {
        it.age > 50
    }.map {
        it.name
    }.take(3).toList()

居然他們的操作符都長(zhǎng)的一樣,效果也都一樣,導(dǎo)致 Sequence 與 Collection 就很類似,那么既生瑜何生亮!為什么需要這么個(gè)東西?既然 Collection 能實(shí)現(xiàn)效果為什么還需要 Sequence 呢?他們的區(qū)別又是什么呢?

區(qū)別與對(duì)比

Collection 是立即執(zhí)行的,每一次中間操作都會(huì)立即執(zhí)行,并且把執(zhí)行的結(jié)果存儲(chǔ)到一個(gè)容器中,沒多一個(gè)中間操作符就多一個(gè)容器存儲(chǔ)結(jié)果。

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
  return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

比如常用的 map 和 filter 都是會(huì)新建一個(gè) ArrayList 去存儲(chǔ)結(jié)果,

Sequence 是延遲執(zhí)行的,它有兩種類型,中間操作和末端操作 ,主要的區(qū)別是中間操作不會(huì)立即執(zhí)行,它們只是被存儲(chǔ)起來,中間操作符會(huì)返回另一個(gè)Sequence,僅當(dāng)末端操作被調(diào)用時(shí),才會(huì)按照順序在每個(gè)元素上執(zhí)行中間操作,然后執(zhí)行末端操作。

public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R> {
    return TransformingSequence(this, transform)
}
public fun <T> Sequence<T>.filter(predicate: (T) -> Boolean): Sequence<T> {
    return FilteringSequence(this, true, predicate)
}

比如常用的 map 和 filter 都是直接返回 Sequence 的this 對(duì)象。

public inline fun <T> Sequence<T>.first(predicate: (T) -> Boolean): T {
    for (element in this) if (predicate(element)) return element
    throw NoSuchElementException("Sequence contains no element matching the predicate.")
}

然后在末端操作中,會(huì)對(duì) Sequence 中的元素進(jìn)行遍歷,直到預(yù)置條件匹配為止。

這里我們舉一個(gè)示例來演示一下:

我們使用同樣的篩選與轉(zhuǎn)換,來看看效果

        val list = mutableListOf<Person>()
        for (i in 1..10000) {
            list.add(Person("name$i", (0..100).random()))
        }
        val time = measureTimeMillis {
            val list1 = list.filter {
                it.age > 50
            }.map {
                it.name
            }.take(3)
            YYLogUtils.w("list1$list1")
        }
        YYLogUtils.w("耗費(fèi)的時(shí)間$time")
        val time2 = measureTimeMillis {
            val list2 = list.asSequence()
                .filter {
                    it.age > 50
                }.map {
                    it.name
                }.take(3).toList()
            YYLogUtils.w("list2$list2")
        }
        YYLogUtils.w("耗費(fèi)的時(shí)間2$time2")

運(yùn)行結(jié)果:

當(dāng)集合數(shù)量為10000的時(shí)候,執(zhí)行時(shí)間能優(yōu)秀百分之50左右:

當(dāng)集合數(shù)量為5000的時(shí)候,執(zhí)行時(shí)間相差比較接近:

當(dāng)集合數(shù)量為3000的時(shí)候,此時(shí)的結(jié)果就反過來了,Sequence延時(shí)執(zhí)行的優(yōu)化效果就不如List轉(zhuǎn)換Sequence再轉(zhuǎn)換List了:

總結(jié)

Collection 會(huì)立即執(zhí)行對(duì)數(shù)據(jù)的操作,而 Sequence 則是延遲執(zhí)行,如果數(shù)據(jù)量比較小,可以使用 Collection ,如果處理的數(shù)據(jù)量比較大,Sequence 是最好的選擇,因?yàn)椴粫?huì)創(chuàng)建中間結(jié)果集,內(nèi)存開銷更小。

根據(jù)上面的測(cè)試發(fā)現(xiàn),也不能無腦的使用 Sequence 來優(yōu)化篩選轉(zhuǎn)換效果,當(dāng)數(shù)據(jù)量沒有達(dá)到一定程度的時(shí)候,可能會(huì)出現(xiàn)負(fù)優(yōu)化的效果。

當(dāng)然我們的對(duì)象是很簡(jiǎn)單的對(duì)象,我們的篩選也是簡(jiǎn)單篩選,當(dāng)對(duì)象復(fù)雜度到一定程度,篩選條件復(fù)雜到一定程度,集合的數(shù)量到一定的程度,我們才可以考慮 使用 Sequence 來達(dá)到優(yōu)化效果。

Sequence 的具體的使用還是需要具體場(chǎng)景具體分析來使用,就我們Android應(yīng)用開發(fā)的場(chǎng)景來說,很少會(huì)出現(xiàn)這么大的數(shù)據(jù)量,所以一般來說我們平常開發(fā)使用 Collection 即可。

好了,本文的全部代碼與Demo都已經(jīng)開源。有興趣可以看這里。項(xiàng)目會(huì)持續(xù)更新,大家可以關(guān)注一下。

以上就是Kotlin的Collection與Sequence操作異同點(diǎn)詳解的詳細(xì)內(nèi)容,更多關(guān)于Kotlin Collection Sequence異同的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論