Search code examples
swiftcombine

Filtering and collecting different elements from two arrays using Combine


I'm trying to combine two arrays using Combine in Swift and filter out the elements that are different between them. I want to collect these different elements into another array using a PassthroughSubject.

Here's my code:

import Combine

let subject1 = PassthroughSubject<[Int], Never>()
let subject2 = PassthroughSubject<[Int], Never>()

subject1.send([4, 5, 6, 8])
subject2.send([4, 5, 7, 9])
subject1.send(completion: .finished)
subject2.send(completion: .finished)

let filteredSubject = PassthroughSubject<[Int], Never>()

Publishers.CombineLatest(subject1, subject2)
    .map { array1, array2 in
        zip(array1, array2)
    }
    .filter { element1, element2 in
        element1 != element2
    }
    .map { element1, _ in
        element1
    }
    .sink { filteredElement in
        filteredSubject.send(filteredElement)
    }
    .store(in: &subscriptions)

filteredSubject
    .sink { filteredElements in
        print("Filtered Elements:", filteredElements)
    }
    .store(in: &subscriptions)

I expect this code to combine subject1 and subject2, filter out the elements that are different between them, and collect these different elements into filteredSubject using a sink. However, it's not printing anything for the filtered elements. What am I missing in my code to achieve the desired result?

Any insights or suggestions would be greatly appreciated.


Solution

  • I would use a Set to simplify the comparisons:

    import UIKit
    
    
    import Combine
    
    let subject1 = PassthroughSubject<[Int], Never>()
    let subject2 = PassthroughSubject<[Int], Never>()
    
    let filteredSubject = PassthroughSubject<[Int], Never>()
    
    var subscriptions = Set<AnyCancellable>()
    
    subject1.combineLatest(subject2)
        .map { array1, array2 -> Set<Int> in
            var set = Set(array1)
            return set.subtracting(array2)
        }.sink { filteredSubject.send( Array<Int>($0)) }
    
    filteredSubject
        .sink { filteredElements in
            print("Filtered Elements:", filteredElements)
        }
        .store(in: &subscriptions)
    
    
    subject1.send([4, 5, 6, 8])
    subject2.send([4, 5, 7, 9])
    subject1.send(completion: .finished)
    subject2.send(completion: .finished)