Iterable<T>相關函式

Functional Programming

原本的集合不會動到,複製一份給其它函式去執行,傳回新的結果。

Iterable.擴展函式()

Iterable是集合,List、Set都是Iterable的子類別,就可以用Iterable.擴展函式()。

以下建立取出第1個元素的泛型擴展函式,並讓list與set使用。

1
2
3
4
5
6
7
8
9
10
fun <T> Iterable<T>.getFirst(): T {
    return this.first()
}

fun main() {
    val list = listOf<String>("Mary", "Alex", "Bill")
    val set1: Set<String> = setOf("Alice", "Mary", "Mary", "Alice")
    println(list.getFirst())
    println(set1.getFirst())
}
Mary
Alice

Iterable是一個Interface,子類別list、set、map會實作iterator(),可以使用Range與for()迴圈,遍歷每個元素。

1
2
3
4
public interface Iterable<out T> {
    // Returns an iterator over the elements of this object.
    public operator fun iterator(): Iterator<T>
}

IntRange

IntRage繼承IntProgression,IntProgression實作Iterator,實作hasNext()、nextInt()函式,遍歷每個元素。

1
2
3
4
5
6
7
8
9
class IntRange(start: Int, end: Int) : IntProgression(start, end, 1) {
    override fun iterator(): IntIterator {
        return object : IntIterator() {
            private var current = first
            override fun hasNext(): Boolean = current <= last
            override fun nextInt(): Int = current++
        }
    }
}
1
2
3
for (i in 2 .. 7) {
    print("$i ")     // 輸出: 2 3 4 5 6 7
}

Iterable.map()擴展函式

Iterable.map()擴展函式,會傳回跟原本集合「一樣大小」的List。
擴展函式程式碼如下:

1
2
3
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

集合元素字串長度

以下程式碼會傳回list元素的長度,傳回新的list,不會修改到原本的list。
it代表每個集合元素。

1
2
3
4
5
fun main() {
    val list = listOf<String>("Mary", "Bill", "Alex", "Ben")
    val result = list.map { it.length }
    println(result)
}
[4, 4, 4, 3]

加上前綴字串

以下程式碼為每個元素加上前綴字串,不會修改原本list,會複製一份新的lis,修改複本傳回。
傳回的list的大小跟原本的list的大小一樣。

1
2
3
4
5
6
fun main() {
    val list = listOf<String>("Mary", "Bill", "Alex", "Ben")
        .map { "Little " + it }
        .map { "Happy " + it }
    println(list)
}
[Happy Little Mary, Happy Little Bill, Happy Little Alex, Happy Little Ben]

flatMap

flatMap主要是把二維List變成一維List。
以下是二維List。

1
val list2d = listOf(listOf(1,2,3), listOf(4,5,6))

flatMap擴展函式,傳入一個空的ArrayList到flatMapTo()函式。

1
2
3
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}

實際真正做事的擴展函式是以下這個。
this是二維List,二維List每個元素都是一維陣列,使用for遍歷二維List,element就是一維陣列。

1
2
3
4
5
6
7
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    for (element in this) {
        val list = transform(element)
        destination.addAll(list)
    }
    return destination
}

二維List

1
val list2d = listOf(listOf(1,2,3), listOf(4,5,6))

第1次循環的element是

1
listOf(1,2,3)

第2次循環的element是

1
listOf(4,5,6)

把每一個元素(一維List),加入到新的ArrayList中。

1
destination.addAll(list)

transform Lambda

每個一維List,傳入transform Lambda。

1
val list = transform(element)

transform類型: (T) -> Iterable,傳入參數為一維List,傳回值是Iterable介面,只要繼承Iterable的子類都可以作為傳回值。

以下Lambda{},參數是一維的list,傳回值也是一維的list。
list也是Iterable的子類。

1
2
val list2d = listOf(listOf(1,2,3), listOf(4,5,6))
val list = list2d.flatMap { innerList -> innerList }

因為參數只有一個,可以用it來取代,it就是一維的list,傳回一維的list。

1
2
val list2d = listOf(listOf(1,2,3), listOf(4,5,6))
val list = list2d.flatMap { it }

完整程式碼:把二維List變成一維List

1
2
3
4
5
6
fun main() {
    val list = listOf(
        listOf(1, 2, 3),
        listOf(4, 5, 6)).flatMap { it }
    println(list)
}
[1, 2, 3, 4, 5, 6]

fold 疊加函式

計算List中元素的總合,total的初始值是0。

1
2
3
4
5
val result = listOf(20, 30, 40).fold(0) {
    total, num ->
    total + num
}
println(result)
90

計算List中元素的總合,total的初始值是5。

1
2
3
4
5
val result = listOf(20, 30, 40).fold(5) {
    total, num ->
    total + num
}
println(result)
95

計算List中 「元素*3」 的總合,total的初始值是5。

1
2
3
4
5
val result = listOf(20, 30, 40).fold(5) {
    total, num ->
    total + num * 3
}
println(result)
275

zip 合併

二種不同的集合,把它們合併變成Pair。

以下有名字的List,年齡的List,透過names.zip(ages)合併後,name變成Key,age變成Value,變成一個Pair物件存在List中,再透過toMap()轉成Map。

1
2
3
4
val names = listOf("Mary", "Bill", "Alex")
val ages = listOf(10, 20, 30)
val map = names.zip(ages).toMap()
println(map["Mary"])
10

results matching ""

    No results matching ""