Collections Functions Part 1

In the next two lessons, we’re gonna cover various functions, which we can use to filter out, group, transform, or simply aggregate elements.


filter

The filter function simply filters elements of a collection based on a given condition (predicate). 

To put it simply, with this function we can get rid of some elements from a collection:

Wait for a second.

I told you previously that we cannot modify elements from an immutable collection

Well, we don’t. The functions we’re going to cover do not modify the initial collection.

In the example above- a completely new collection was created containing elements after filtering. 


map

The map function allows us to transform each element of our collection:

Moreover, we can chain our functions, as well:

Question 1

Could you tell me why should we perform filtering before mapping in such a case?

Well, as I mentioned previously- each operation creates a new collection.

So, from the performance perspective, it’s better to first remove unwanted items, and then perform mapping on the elements, we want to have in the end.

Otherwise, we would waste resources mapping 5 elements, and then filtering out the results.


Exercise 1

Please process the strList in the following manner: 

  1. Firstly, filter out strings shorter than 4 characters. 
  2. Then please convert the remaining string to uppercase. 
  3. Lastly, please reverse the uppercase strings.

fun main() {
  val strList = listOf("apple", "banana", "cherry", "kiwi", "mango", "orange")

  val processed = strList
    .filter { it.length >= 4 }
    .map { it.uppercase() }
    .map { it.reversed() }

  println("Final list: $processed")
}


flatMap

The flatMap transforms elements of a collection into new collections and then combines them into a single collection. 

Sounds weird, right? 

Let’s take a look at the example:

As we can see, we ended up in a weird situation with a list containing lists of names (yes, it is possible, and also happens sometimes). 

The flatMap was invoked twice: for the first nested list containing Alice and Bob, and for the second nested list. Each time, we simply returned the same, nested list and flatMap took elements from these lists and combined them together, in one, flattened list. 

Could you predict what’s gonna happen in the following code snippet?

Note: the toList() function can be used to create a list from the element: 

fun main() {
  val names = listOf("Alice", "Bob", "Charlie", "Ada")
  val result = names
    .filter { name -> name.length > 3 }
    .map { name -> name.uppercase() }
    .flatMap { name -> name.toList() }

  println(result)  // [A, L, I, C, E, C, H, A, R, L, I, E]
}


flatten

Although we can “extract” the nested list manually, using the flatMap, the flatten function might be a better choice:


sorted / sortedBy

If we would like to sort elements, then we can make use of either the sorted or the sortedBy:

  • sorted– returns a new collection containing the elements sorted according to their natural order or by a custom comparator.
  • sortedBy– returns a new collection containing the elements sorted according to a given function (selector).

 

Let’s take a look at the following code snippet:

As we can see, the first list was sorted according to the natural order of numbers, nothing unexpected.

When it comes to the sortedBy, as the selector, we’ve chosen the length of each name. The length value is nothing else than an Int, so values were sorted with lengths ascending. 

But what if we would like to reverse the order? 

Well, we can either use sortedDescending, sortedByDescending, or apply the reversed:


Exercise 2

Please process the listOfLists in the following way: 

  1. Firstly, please flatten the lists of integers into a single list. 
  2. Then, please sort it in the ascending order.

fun main() {
  val listOfLists = listOf(
    listOf(5, 3, 8),
    listOf(1, 7, 2),
    listOf(9, 6, 4)
  )

  val processed =
    listOfLists.flatten()
      .sorted()

  println("Final list: $processed")
}


any / all / none

These 3 functions are really similar and return a Boolean value indicating, whether:

  • any- any value in our collection meets particular criteria,
  • all- all values meet our criteria,
  • none- no value meets our criteria (the opposite of all).

 

Let’s take a look at examples:


sum / sumOf

The sum function simply returns the sum of all elements in the collection.

The sumOf, on the other hand, calculates the sum of all elements in the collection after transforming them using a given function.

Let’s take the following code:

As we can see, although the sumOf looks pretty similar to the ones we’ve already covered above, we can’t pass any condition there. 

Instead, we have to return a number within curly brackets. Moreover, the above code is a good example that we even do not have to use the values from the collection – we simply assign 12.0 points for each element in the collection. 


Exercise 3

Please find the following tasks for the strList:

  1. Please check whether any string is longer than 5 characters. 
  2. Please verify if all strings start with a lowercase letter. 
  3. Please check if none of the strings in the list contains a digit (hint: each string is an array of chars).
  4. Please calculate the sum of the lengths of the strings.  

fun main() {
  val strList = listOf("apple", "banana", "cherry", "kiwi", "mango", "orange")

  val anyLongerThan5 = strList.any { it.length > 5 }
  val allStartWithLowercase = strList.all { it.first().isLowerCase() }
  val noneContainsDigit = strList.none { it.any { c -> c.isDigit() } }
  val lengthSum = strList.sumOf { it.length }

  println("Any string longer than 5 characters: $anyLongerThan5")
  println("All strings start with a lowercase letter: $allStartWithLowercase")
  println("None of the strings contains a digit: $noneContainsDigit")
  println("Sum of lengths of the strings: $lengthSum")
}


fold / reduce

The fold and reduce allow us to accumulate of our collection using our custom operation.

The main difference is that fold allows us to provide some initial value:


Exercise 4

Please perform the following task for the intList

  1. Please calculate the product of the elements. 
  2. Please calculate the sum of the elements in the list using fold

fun main() {
  val intList = listOf(1, 2, 3, 4, 5)

  val product = intList.reduce { acc, i -> acc * i }

  val initialValue = 0
  val sumWithInitialValue = intList.fold(initialValue) { acc, i -> acc + i }

  println("Product of the elements in the list: $product")
  println("Sum of the elements in the list: $sumWithInitialValue")
}
Complete and Continue  
Discussion

0 comments