This is Understanding Combine, written by Matt Neuburg. It is a work in progress. Corrections and suggestions are greatly appreciated (you can comment here). So are donations; please consider keeping me going by funding this work at Or buy my books: the current editions are iOS 13 Programming Fundamentals with Swift and Programming iOS 13. Thank you!


.removeDuplicates (Publishers.RemoveDuplicates) can be thought of as a specialized form of .filter; it is also related to .scan. Somewhat like .scan, it keeps track of the previous value that it received from upstream; like .filter, it decides whether to stop the current value that arrives from upstream, but it can do this based on something about the previous value.

By default, .removeDuplicates uses a simple equality test: if the current value is the same as the previous value, it is blocked. However, you can append a filter function that receives two values — the previous value, followed by the current value — and returns a Bool saying whether the current value should be blocked. Note that this is the inverse of the Bool you return in the .filter filter function: with .filter, true means “let it through,” but with with .removeDuplicates, true means “block it.”

Observe that the first value is always passed through .removeDuplicates without calling the filter function.

There is also a .tryRemoveDuplicates (Publishers.TryRemoveDuplicates); it adds to the filter function the ability to throw an error which is passed down the pipeline as a failure.

Table of Contents