## 1. Introduction

Scala provides very powerful *Collection* data structures in the standard library. The Scala collections library provides various methods/functions to process and manipulate data in our collection.

In this tutorial, we’ll **explore different techniques to filter elements from a collection. We’ll focus on the find, filter, and collect methods** and their respective variations.

Collections in Scala are immutable by default. Therefore, the methods we’ll see return new collections after applying the transformation to the input. In other words, these methods won’t modify the existing collections.

Unless specifically mentioned, these methods can be applied to all collection types, such as *List*, *Array*, and so on.

## 2. *find* Method

**The find method on a Scala collection returns the first element matching the predicate as an Option value**. If there is no matching element, it returns

*None*.

Let’s look at a simple example to understand this:

```
val numbers = List(1, 2, 3, 4, 5, 6)
numbers.find(_ % 2 == 0) shouldBe Some(2)
numbers.find(_ > 9) shouldBe None
```

**The find method utilizes the underlying collection’s ordering to find the first match**.

In linear collections such as *List*, *Seq*, *Array*, and so on, we can use the method *findLast* to find the last element that matches the predicate:

```
val numbers = List(1, 2, 3, 4, 5, 6)
numbers.findLast(_ % 2 == 0) shouldBe Some(6)
```

However, we should note that this isn’t available on non-linear collections such as *Set*.

## 3. *filter* Method

We can **use the filter method to select a set of elements from a collection matching a predicate**.

Let’s look at a simple example:

```
val numbers: List[Int] = List(1, 2, 3, 4, 5, 6)
val oddNumbers: List[Int] = numbers.filter(_ % 2 == 1)
oddNumbers shouldBe List(1, 3, 5)
```

If none of the elements match the predicate, it returns an empty collection of the same type:

```
val numbers = List(2, 4, 6, 8)
val oddNumbers = numbers.filter(_ % 2 == 1)
oddNumbers shouldBe empty
```

We can also provide a complex predicate in the *filter* method:

```
val numbers = List(1, 2, 3, 4, 5, 6)
val oddAndNotMulOf3or5 =
numbers.filter(n => (n % 2 == 1 && n % 3 != 0 && n % 5 != 0))
oddAndNotMulOf3or5 shouldBe List(1)
```

Moreover, we can **extract the complex condition into a method and then pass it on to the filter method**. Let’s create a method corresponding to the complex predicate:

```
def isOddAndNotMulOf3or5(n: Int) =
n % 2 == 1 && n % 3 != 0 && n % 5 != 0
```

Now, we can apply this method to the *filter* method:

```
val numbers = List(1, 2, 3, 4, 5, 6)
val oddAndNotMulOf3or5 =
numbers.filter(isOddAndNotMulOf3or5)
oddAndNotMulOf3or5 shouldBe List(1)
```

**Under the hood, Scala converts the method isOddAndNotMulOf3or5 into a function using eta expansion and applies the predicate to the filter method**.

Scala offers an alternate method *filterNot* that inverts the condition. **The filterNot method returns elements that don’t match the predicate condition**:

```
val numbers = List(1, 2, 3, 4, 5, 6)
val nonOdd = numbers.filterNot(_ % 2 == 1)
val even = numbers.filter(_ % 2 != 1)
nonOdd shouldBe even
```

Here, both *nonOdd* and *even* variables should have the same values.

## 4. *collect* Method

We can also choose elements that meet a specific condition by using the *collect* method.** Instead of a predicate function like with the filter method, collect uses a partial function**.

Let’s rewrite the previous *filter* example using the* collect* method:

```
val numbers = List(1, 2, 3, 4, 5, 6)
val even = numbers.collect {
case n if n % 2 == 0 => n
}
even shouldBe List(2, 4, 6)
```

This looks more complicated and verbose than using a *filter* method. Nonetheless, **the advantage of using the collect method lies in its capability to filter elements based on a given condition and transform the matching values**. That means it combines the power of

*filter*and

*map*into a single method.

For example, let’s assume that we need to find the square of the even numbers:

```
val numbers = List(1, 2, 3, 4, 5, 6)
val even = numbers.collect {
case n if n % 2 == 0 => n * n
}
even shouldBe List(4, 16, 36)
```

This is comparable to the below code that uses *filter* and *map*:

```
val numbers = List(1, 2, 3, 4, 5, 6)
val evenSquared = numbers.filter(_ % 2 == 0).map(n => n * n)
evenSquared shouldBe List(4, 16, 36)
```

Additionally, we can use the method *collectFirst* to process only the first matching element:

```
val numbers = List(1, 2, 3, 4, 5, 6)
val firstEven = numbers.collectFirst {
case n if n % 2 == 0 => n
}
firstEven shouldBe Some(2)
```

**The collect method can be likened to filter, while collectFirst can be likened to find**. However, there is no method with the name

*collectLast*. One of the ways to implement this is by reversing the collection and applying

*collectFirst*on it.

## 5. Conclusion

In this article, we discussed the most common methods to filter elements from a collection. The methods *find*, *filter*, and *collect *can be used based on the requirement. We also looked at some variations of these methods.

The methods we discussed are the most popular ones for filtering elements. It’s worth noting that more methods, such as *span*, *partition*, and so on, can also be used to do some filtering.

As always, the sample code used in this tutorial is available over on GitHub.