# 4 Filtering Operators Written by Shai Mishali

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

As you might have realized by now, operators are basically the vocabulary that you use to manipulate Combine publishers. The more “words” you know, the better your control of your data will be.

In the previous chapter, you learned how to consume values and transform them into different values — definitely one of the most useful operator categories for your daily work.

But what happens when you want to limit the values or events emitted by the publisher, and only consume some of them? This chapter is all about how to do this with a special group of operators: Filtering operators!

Luckily, many of these operators have parallels with the same names in the Swift standard library, so don’t be surprised if you’re able to filter some of this chapter’s content. :]

It’s time to dive right in.

## Getting started

You can find the starter playground for this chapter, Starter.playground, in the projects folder. As you progress through this chapter, you’ll write code in the playground and then run the playground. This will help you understand how different operators manipulate events emitted by your publisher.

Note: Most operators in this chapter have parallels with a `try` prefix, for example, `filter` vs. `tryFilter`. The only difference between them is that the latter provides a throwing closure. Any error you throw from within the closure will terminate the publisher with the thrown error. For brevity’s sake, this chapter will only cover the non-throwing variations, since they are virtually identical.

## Filtering basics

This first section will deal with the basics of filtering — consuming a publisher of values and conditionally deciding which of them to pass to the consumer.

``````example(of: "filter") {
// 1
let numbers = (1...10).publisher

// 2
numbers
.filter { \$0.isMultiple(of: 3) }
print("\(n) is a multiple of 3!")
})
.store(in: &subscriptions)
}
``````
``````——— Example of: filter ———
3 is a multiple of 3!
6 is a multiple of 3!
9 is a multiple of 3!
``````

``````example(of: "removeDuplicates") {
// 1
let words = "hey hey there! want to listen to mister mister ?"
.components(separatedBy: " ")
.publisher
// 2
words
.removeDuplicates()
.store(in: &subscriptions)
}
``````
``````——— Example of: removeDuplicates ———
hey
there!
want
to
listen
to
mister
?
``````

## Compacting and ignoring

Quite often, you’ll find yourself dealing with a publisher emitting `Optional` values. Or even more commonly, you’ll want to perform some operation on your values that might return `nil`, but who wants to handle all those `nil`s ?!

``````example(of: "compactMap") {
// 1
let strings = ["a", "1.24", "3",
"def", "45", "0.23"].publisher

// 2
strings
.compactMap { Float(\$0) }
// 3
print(\$0)
})
.store(in: &subscriptions)
}
``````
``````——— Example of: compactMap ———
1.24
3.0
45.0
0.23
``````

``````example(of: "ignoreOutput") {
// 1
let numbers = (1...10_000).publisher

// 2
numbers
.ignoreOutput()
.sink(receiveCompletion: { print("Completed with: \(\$0)") },
.store(in: &subscriptions)
}
``````
``````——— Example of: ignoreOutput ———
Completed with: finished
``````

## Finding values

In this section, you’ll learn about two operators that also have their origins in the Swift standard library: `first(where:)` and `last(where:)`. As their names imply, you use them to find and emit only the first or the last value matching the provided predicate, respectively.

``````example(of: "first(where:)") {
// 1
let numbers = (1...9).publisher

// 2
numbers
.first(where: { \$0 % 2 == 0 })
.sink(receiveCompletion: { print("Completed with: \(\$0)") },
.store(in: &subscriptions)
}
``````
``````——— Example of: first(where:) ———
2
Completed with: finished
``````
``````numbers
``````
``````numbers
.print("numbers")
``````
``````——— Example of: first(where:) ———
numbers: request unlimited
2
Completed with: finished
``````

``````example(of: "last(where:)") {
// 1
let numbers = (1...9).publisher

// 2
numbers
.last(where: { \$0 % 2 == 0 })
.sink(receiveCompletion: { print("Completed with: \(\$0)") },
.store(in: &subscriptions)
}
``````
``````——— Example of: last(where:) ———
8
Completed with: finished
``````
``````example(of: "last(where:)") {
let numbers = PassthroughSubject<Int, Never>()

numbers
.last(where: { \$0 % 2 == 0 })
.sink(receiveCompletion: { print("Completed with: \(\$0)") },
.store(in: &subscriptions)

numbers.send(1)
numbers.send(2)
numbers.send(3)
numbers.send(4)
numbers.send(5)
}
``````
``````——— Example of: last(where:) ———
``````
``````numbers.send(completion: .finished)
``````
``````——— Example of: last(where:) ———
4
Completed with: finished
``````

## Dropping values

Dropping values is a useful capability you’ll often need to leverage when working with publishers. For example, you can use it when you want to ignore values from one publisher until a second one starts publishing, or if you want to ignore a specific amount of values at the start of the stream.

``````example(of: "dropFirst") {
// 1
let numbers = (1...10).publisher

// 2
numbers
.dropFirst(8)
.store(in: &subscriptions)
}
``````
``````——— Example of: dropFirst ———
9
10
``````

``````example(of: "drop(while:)") {
// 1
let numbers = (1...10).publisher

// 2
numbers
.drop(while: { \$0 % 5 != 0 })
.store(in: &subscriptions)
}
``````
``````——— Example of: drop(while:) ———
5
6
7
8
9
10
``````
``````.drop(while: { \$0 % 5 != 0 })
``````
``````.drop(while: {
print("x")
return \$0 % 5 != 0
})
``````
``````——— Example of: drop(while:) ———
x
x
x
x
x
5
6
7
8
9
10
``````

``````example(of: "drop(untilOutputFrom:)") {
// 1
let taps = PassthroughSubject<Int, Never>()

// 2
taps
.store(in: &subscriptions)

// 3
(1...5).forEach { n in
taps.send(n)

if n == 3 {
}
}
}
``````
``````——— Example of: drop(untilOutputFrom:) ———
4
5
``````

## Limiting values

In the previous section, you’ve learned how to drop — or skip — values until a certain condition is met. That condition could be either matching some static value, a predicate closure, or a dependency on a different publisher.

``````example(of: "prefix") {
// 1
let numbers = (1...10).publisher

// 2
numbers
.prefix(2)
.sink(receiveCompletion: { print("Completed with: \(\$0)") },
.store(in: &subscriptions)
}
``````
``````——— Example of: prefix ———
1
2
Completed with: finished
``````

``````example(of: "prefix(while:)") {
// 1
let numbers = (1...10).publisher

// 2
numbers
.prefix(while: { \$0 < 3 })
.sink(receiveCompletion: { print("Completed with: \(\$0)") },
.store(in: &subscriptions)
}
``````
``````——— Example of: prefix(while:) ———
1
2
Completed with: finished
``````

``````example(of: "prefix(untilOutputFrom:)") {
// 1
let taps = PassthroughSubject<Int, Never>()

// 2
taps
.sink(receiveCompletion: { print("Completed with: \(\$0)") },
.store(in: &subscriptions)

// 3
(1...5).forEach { n in
taps.send(n)

if n == 2 {
}
}
}
``````
``````——— Example of: prefix(untilOutputFrom:) ———
1
2
Completed with: finished
``````

## Challenge

You have quite a lot of filtering knowledge at your disposal now. Why not try a short challenge?

### Challenge: Filter all the things

Create an example that publishes a collection of numbers from `1` through `100`, and use filtering operators to:

## Key points

In this chapter, you learned that:

## Where to go from here?

Wow, what a ride this chapter has been! You should rightfully feel like a master of filtering, ready to channel these upstream values in any way you desire.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below: