This is the 14th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
preface
In the last article, I mainly explained Kotlin’s corresponding generics and extension functions. In this article, we will cover functional programming in Kotlin.
No more words, just get started!
1. The map {}
Before using a function, first analyze the source code:
.map source
public inline fun <T, R>可迭代<T>.map(transform: (T) - >R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
Copy the code
Analysis:
Iterable<T>.map(transform: (T) -> R): List<R>
We know from this sentence,.map
The user toIterable<T>
Set type;: List<R>
This is the whole thing.map
The function returns another list of collections, with values and corresponding types specified bymapTo
Method determination;transform: (T) -> R
Because T is in parentheses, it means that by default in the Map closure it represents a single element, and the return value type is the single element type of the collection
CollectionSizeOrDefault; mapTo;
CollectionSizeOrDefault source
internal fun <T>可迭代<T>.collectionSizeOrDefault(default: Int): Int =
if (this is Collection<*>) this.size else default
Copy the code
As you can see from this source line, return the size of the iterable if known, otherwise return the specified default value of 10!
Define a new collection here, prepare to receive logic to assemble the new collection, and return the assembled combination as List
.
The following
MapTo source
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) - >R): C {
for (item in this)
destination.add(transform(item))
return destination
}
Copy the code
Analysis:
fun<T, R, C : MutableCollection<in R>>
This code declares the corresponding generic,- T represents a single element type in the original set
- R represents the single element type in the new collection
- C represents the new collection to be returned. The inside of the
<in R>
This stands for contravariant, similar to Java? super R
destination: C
This means that the top passesArrayList<R>(collectionSizeOrDefault(10))
A new collection of defined data to be assembledtransform: (T) -> R
This is also the method passed in by the previous method!for (item in this) destination.add(transform(item)) return destination Copy the code
destination.add(transform(item))
From this code, we can see that the core logic implemented in the closure will be re-passedtransform
Method to regenerate new elements, then add them to the new collection, and finally return them!
The theoretical analysis is finished, the principle is also known, now to practical practice some time!
fun main{
val animals = listOf("zebra"."giraffe"."elephant"."rat")
val babies = animals
// Animal is equal to every element in the set animals
// map traverses the entire object and returns the traversed object to the upper level
// In the map, there is A baby before each element, so there is A baby before each element in the set
.map { animal -> "A baby $animal" }
// Where baby is equal to the object traversed in the latest set of maps
.map { baby -> "$baby ,with the cutest little tail ever!" }
// Since println does not return any value, it returns a collection of elements with no return value
.map { item -> println(item) }
println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --")
println(animals)
println(babies)
}
Copy the code
Now that we know how it works, is it easy to write code? Let’s see how it works:
A baby zebra ,with the cutest little tail ever!
A baby giraffe ,with the cutest little tail ever!
A baby elephant ,with the cutest little tail ever!
A baby rat ,with the cutest little tail ever!
---------------------------
[zebra, giraffe, elephant, rat]
[kotlin.Unit, kotlin.Unit, kotlin.Unit, kotlin.Unit]
Copy the code
Note: the animal – >, baby – > item – > can use the default it directly, so there is support for custom name it.
2. The filter {}
As always, the first analysis of the source code, as long as you follow my blog to see this, I believe you should have a certain analysis of the source code ability, so behind the analysis to hurry up (unlike the previous step by step analysis).
To enter. The filter
public inline fun <T>可迭代<T>.filter(predicate: (T) - >Boolean): List<T> {
return filterTo(ArrayList<T>(), predicate)
}
Copy the code
We see that the return value is a List
collection, and the return value and the corresponding type are determined by filterTo, so
Enter the filterTo
public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) - >Boolean): C {
for (element in this) if (predicate(element)) destination.add(element)
return destination
}
Copy the code
For (element in this) if (predicate(element)) destination.add(element) If the elements meet the conditions of the predicate method, they are added to the set to be returned.
In other words, this method filters every element in the set. Those that meet the criteria are left behind and those that do not meet the criteria are removed.
Let’s see how it works:
fun main{
val result = listOf("Jack"."Jimmy"."Rose"."Tom")
// filter indicates the set filter, corresponding to the data whose expression is true
.filter { it.contains("J") }
println(result)
}
Copy the code
Running effect
[Jack, Jimmy]
Copy the code
Let’s see if it’s easy to learn Kotlin and run it exactly as you want.
3,. Flatten ()
Take a look at the source code:
public fun <T>可迭代<Iterable<T>>.flatten(a): List<T> {
val result = ArrayList<T>()
for (element in this) {
result.addAll(element)
}
return result
}
Copy the code
Through this code can be seen at a glance is multiple collections, merge into a collection of functions.
If you can’t see it at first glance, then look at it more, hahaha.
In this case it is easy to use!
fun main{
val result =
listOf(listOf(1.2.3), listOf(4.5.6), listOf("Zhang"."Bill")).flatten()
println(result)
}
Copy the code
Running effect
[1, 2, 3, 4, 5, 6, Zhang SAN, Li Si]Copy the code
Perfect, the so-called know yourself and know your enemy, can win every battle, in this respect can be handy. Next!
4,. FlatMap {}
Look at the source
Enter the flatMap.
public inline fun <T, R>可迭代<T>.flatMap(transform: (T) - >可迭代<R>): List<R> {
return flatMapTo(ArrayList<R>(), transform)
}
Copy the code
Seeing this without further ado, go straight to the flatMapTo method
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) - >可迭代<R>): C {
for (element in this) {
val list = transform(element)
destination.addAll(list)
}
return destination
}
Copy the code
This is almost the same as merging the collections above, except that the transform method is called before merging the collections. The transform method corresponding logic is implemented by the developer himself. So give it a try?
fun main{
val items = listOf(
listOf("red apple"."green apple"."blue apple"),
listOf("red fish"."blue fish"),
listOf("yellow banana"."teal banana"))// This operation means that the filtered collection contains red data and merges the filtered multidimensional collection/array
val redItems = items.flatMap { it.filter { item-> item.contains("red") } }
println(redItems)
}
Copy the code
The logic we implement here is to filter the corresponding elements by.filter, get the matching set, and merge the corresponding set into an array by flatMap!
Running effect
[red apple, red fish]
Copy the code
Nice! That’s how it works!
5. None {}
Look at the source
public inline fun <T>可迭代<T>.none(predicate: (T) - >Boolean): Boolean {
if (this is Collection && isEmpty()) return true
for (element in this) if (predicate(element)) return false
return true
}
Copy the code
And here we see that this method none actually returns false only if it satisfies the predicate method, and true in all other cases.
Boolean is needed to filter elements. Try it out
Write a prime number filter: a prime number is not divisible by itself and 1.
fun main{
val numbers = listOf(7.4.8.4.3.22.18.11)
// Remember that filter stands for set filter, so use it if you have any criteria
valprimes = numbers.filter { number -> ! (2 until number).map {// So let's take an inverse here, which means we only need composite number analysis 3
number % it // If the remainder returns 0, it can be divisible by a number other than itself
}.none { it == 0 } // If the remainder is 0, it is composite, because true is false
}
println(primes)
}
Copy the code
Running effect
[4, 8, 4, 22, 18]
Copy the code
Logic is in the annotation, according to the analysis steps to see OK!
6, zip ().
As the name implies, ZIP feels like file packaging compression, or several files packed into a single file.
Look at the source code first
public infix fun <T, R>可迭代<T>.zip(other: 可迭代<R>): List<Pair<T, R>> {
return zip(other) { t1, t2 -> t1 to t2 }
}
Copy the code
Enter the next layer of source code
public inline fun <T, R, V>可迭代<T>.zip(other: 可迭代<R>, transform: (a: T.b: R) - >V): List<V> {
val first = iterator()
val second = other.iterator()
val list = ArrayList<V>(minOf(collectionSizeOrDefault(10), other.collectionSizeOrDefault(10)))
while (first.hasNext() && second.hasNext()) {
list.add(transform(first.next(), second.next()))
}
return list
}
Copy the code
To get straight to the point, in the while loop list.add(transform(first.next(), second.next()))) means to compress two collections into a single collection using the transform method.
The corresponding transform method is the implementation of the upper-layer {T1, T2 -> T1 to T2} code block.
Let’s see how it works:
fun main{
val employees = listOf("Jack"."Jason"."Tommy")
val shirtSize = listOf("large"."x-large"."medium")
// Zip combines multiple collections into a single object, which can be converted into a map or a list
val employeeShirtSizes=employees.zip(shirtSize)
println(employeeShirtSizes)
}
Copy the code
Running effect
[(Jack, large), (Jason, x-large), (Tommy, medium)]
Copy the code
So I can go to the map and the corresponding list, so let’s see, okay?
7,. ToMap ()
Now that you know what it does, start using it.
fun main{
val employees = listOf("Jack"."Jason"."Tommy")
val shirtSize = listOf("large"."x-large"."medium")
// Zip combines multiple collections into a single object, which can be converted into a map or a list
val employeeShirtSizes=employees.zip(shirtSize).toMap()
val list = employeeShirtSizes.map { "key= ${it.key}, value=${it.value} \t" }
println(list)
}
Copy the code
Running effect
[key= Jack, value=large , key= Jason, value=x-large , key= Tommy, value=medium ]
Copy the code
There is nothing to say, readers can also try to turn the list to play, here do not try, directly to the next!
8. A fold () {}
Keep looking at the source code
public inline fun <T, R>可迭代<T>.fold(initial: R, operation: (acc: R.T) - >R): R {
var accumulator = initial
for (element in this) accumulator = operation(accumulator, element)
return accumulator
}
Copy the code
Source code analysis:
initial: R
The saidfold(a)
The value of a, which means,accumulator
forfold(a)
Value of method A;- Then look at
for (element in this) accumulator = operation(accumulator, element)
This code: - This code:
accumulator = operation(accumulator, element)
Represents each calloperation
Method, assigns the result of the method toaccumulator
; - When the next loop is executed, the last result value is used as
operation
The first parameter to the method is passed in, and the result of the method is assigned toaccumulator
And so the cycle ends!
Analysis finished, look at the use!
fun main{
// fold indicates that the collection traversal will carry the corresponding variable into the collection traversal loop as the initial value. The first traversal object will carry the initial value, and the second one will carry the collection item
val foledValue = listOf(1.2.3.4).fold(3) { accmulator, number ->
println("Accmulator value:$accmulator,number value:$number")
accmulator + (number * 3)
}
println("Final value:$foledValue")}Copy the code
Running effect
Accmulator value:3,number value:1
Accmulator value:6,number value:2
Accmulator value:12,number value:3
Accmulator value:21,number value:4
Final value:33
Copy the code
The value of accmulator is fold(3). The value of accmulator is the result of the last loop.
9,. Take ()
Look at the source code first
public fun <T>可迭代<T>.take(n: Int): List<T> {
require(n >= 0) { "Requested element count $n is less than zero." }
if (n == 0) return emptyList()
if (this is Collection<T>) {
if (n >= size) return toList()
if (n == 1) return listOf(first())
}
var count = 0
val list = ArrayList<T>(n)
for (item in this) {
list.add(item)
if (++count == n)
break
}
return list.optimizeReadOnlyList()
}
Copy the code
Take a closer look at this code:
for (item in this) {
list.add(item)
if (++count == n)
break
}
Copy the code
At first glance it looks like a collection of length n at most, try it!
fun Int.isPrime(a): Boolean{(2 until this).map {
if (this % it == 0) {
return false}}return true
}
fun main{
val toList = (1.5000.).toList().filter { it.isPrime() }.take(1000)
println("Between 5,000 and, at most, 1,000 primes, find${toList.size}The last prime number is:${toList[toList.size - 1]}")
val oneTousandPrimes = generateSequence(2) { value ->
value + 1
}.filter { it.isPrime() }.take(1000)
val listPrimes = oneTousandPrimes.toList()
println("Find at most 1000 prime numbers in the case of automatic growth of natural numbers, and find${listPrimes.size}The last prime number is:${listPrimes[listPrimes.size - 1]}")}Copy the code
Take a look at the results:
Between 5000 and 1000 prime numbers, find 670 prime numbers, the last prime number is 4999. In the case of automatic growth of natural numbers, find 1000 prime numbers, find 1000 prime numbers, and find 7919 prime numbersCopy the code
conclusion
Well, that’s about the end of this piece. As will be explained in the next article, Kotlin and Java call each other!