Common Operations on collections – Kotlin

In this section, you’ll learn the common operations that are used for working with collections in a functional style. As we’ve already discussed, the Kotlin standard library consists mostly of extensions on Java collections. A lot of these extensions work with the collections in a functional style and use lambdas. For instance, filter and map are defined in the Kotlin standard library as extension functions.

for example: what is the Avg age of employees working in Delhi?

val employees:List<Employee>
data class Employee(val city:String,val age:Int)

employees.filter { it.city == City.Delhi }.map { it.age }.average()

As you can see there is three extension function in the above coding block i.e filter, map, and average. so let’s discuss all standard methods.

1.Filter

It filters out the content of the list and keeps only their elements that satisfy the given predicate. In this case, we have the predicate checking that a number is even and only even numbers that are present in the resulting list. 

val list = listOf(1, 2, 3, 4, 5, 6)
list .filter { it % 2 == 0 }

2. Map

Map transform each element in a collection and stores all the resulting elements in a new list. Here, we find the square of each given number and the result is a list of squares. Now to that, the resulting list contains as many elements as the initial collection. 

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

3. Any, All and None

There are several predicates checking whether the given facts about the elements are true.

any returns true if at least one element matches the given predicate. none return true if none of the elements match the given predicate. all return true if all elements match the given predicate.

val list = listOf(1, 2, 3, 4, 5, 6)
list.any { it % 2 == 0 }
list.all { it % 2 == 0 }
list.none{ it % 2 == 0 }

4. find

Find finds an element satisfying the given predicate and returns it as a result. If there is no required element, find returns null. 

val list = listOf(1, 2, 3, 4, 5, 6)
list.find { it % 2 == 0 }

5. first / firstOrNull

Returns the first element matching the given predicate, or null if the element was not found.

val list = listOf(1, 2, 3, 4, 5, 6)
list.find { it % 2 == 0 } => retuen 2

6. count

 Count counts the number of elements that satisfy the given predicate. 

val list = listOf(1, 2, 3, 4, 5, 6)
list.find { it % 2 == 0 } => retuen 3 count

7. partition

partition divides the collection into two collections. Filter returns only the elements that satisfy the predicate, and in a sense, throws out all the elements that don’t satisfy the predicate. If you need to keep both groups of elements that satisfy or do not satisfy the predicate, you can use the partition. It returns two collections, for the good elements and the remaining ones. 

val list = listOf(1 , 2, 3, 4, 5)
val (even, odd) = list.partition{ it % 2 == 0}

8. groupBy

If you need to divide your collection into more than two groups, you can use GroupBy. As an argument, you provide the way how to group the elements. What should be the grouping key? For instance, here we group personal elements by their age. The result is map from the given key to a list of elements that satisfy this scheme.

val age = listOf(23, 23, 50, 56, 35, 50)
val ageMapGroup = age.groupBy{ it }

print(ageMapGroup.values)

output:
[[23, 23], [50, 50], [56], [35]]

9. associateBy

 It also performs groping, but it returns you one element as the map value. Note that, associateBy should be used to run the keys unique. If it’s not, pay attention that duplicates are removed, so the last element will be chosen. If your key isn’t unique, it’s safer to use groupBy to avoid losing some of the elements. You can use it as an associate to build a map based on a list.

# It Remove Duplicate Values

val age = listOf(23, 23, 50, 56, 35, 50)
val ageMapGroup = age.associateBy{ it }

print(ageMapGroup.keys)
print(ageMapGroup.values)

output:
[23, 50, 56, 35]
[23, 50, 56, 35]

10. associate

associate builds a map by filling in specified keys and values. The first value in a pair becomes key in the map, the second becomes the value. Here, an ‘it’ plus one it specifies how to create keys, while 10 multiply, it is the way to create values. Note that, it’s often convenient to use the least element as a key and provide a way to fetch the value in the lambda.

val age = listOf(23, 23, 50, 56, 35, 50)
val ageMapGroup = age.associate{ it + 1  to it*2 }

print(ageMapGroup.keys)
print(ageMapGroup.values)

output:
[24, 51, 57, 36]
[46, 100, 112, 70]

11. Zip

Zip provides you with a way to organize a couple of lists. It zips like a zipper the elements from two lists. It returns you a list of pairs where each pair contains one element from the first list and another element from the second list. If their initial list has different sizes, then the resulting list of pairs will have the length of the shortest list, the remaining elements from the longest list will be ignored. 

val A = listOf("a", "b", "c")
val B = listOf(1, 2, 3, 4)  
val resultPairs = A.zip(B)

output:
[(a, 1), (b, 2), (c, 3)]

12. zipWithNext

The frequent use case is to zip neighboring elements in the list. That can be done with the help of the zipWithNext function. It returns you a list of pairs where each pair consists of neighboring elements is from the initial list

val A = listOf("a", "b", "c", "d") 
val resultPairs = A.zipWithNext()
print(resultPairs)

output:
[(a, b), (b, c), (c, d)]

13. flatten

Flatten is an extension function that must be called on a list of lists. It combines all the elements from the nested list and returns you a list of these elements as the result. We can say, it flattens the list of lists contents. 

val deepArray = arrayOf(
    arrayOf(1),
    arrayOf(2, 3)
)

println(deepArray.flatten())

output:
[1, 2, 3]

14. flatMap

With flatMap, you can “flatten” multiple Data:: items into one collection as shown with the items variable. Using the map, on the other hand, simply results in a list of lists.

  val data = listOf(Data(listOf("a", "b", "c")), Data(listOf("1", "2", "3")))
   val items: List<String> = data.flatMap { it.items } => [a, b, c, 1, 2, 3]