Skip to content

Instantly share code, notes, and snippets.

@chrislconover
Last active February 2, 2018 01:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrislconover/ac344ec28c118f8e4a922795fbf59983 to your computer and use it in GitHub Desktop.
Save chrislconover/ac344ec28c118f8e4a922795fbf59983 to your computer and use it in GitHub Desktop.
Diffing RxSwift observables
let v = Variable<[Int]>([1, 2, 3])
let withDiffs = v.asObservable().withDiffs(startingWith: [])
.subscribe(onNext: { print("With diffs: \($0)") })
let justDiffs = v.asObservable().diffs(startingWith: [])
.subscribe(onNext: { print("Just diffs: \($0)") })
v.value = [1, 3, 4]
prints:
> Got diffs: ([1, 3, 4], [D(1), I(2,4)])
> Just diffs: [D(1), I(2,4)]
// Created by Chris Conover on 1/27/18.
import Differ
import RxSwift
extension ObservableType where E:Collection, E.Iterator.Element: Equatable {
func withDiffs(startingWith first: E) -> Observable<(E, [Patch<E.Element>])> {
return withPrevious(startWith: first)
.map { from, to in (to, from.diff(to).patch(from: from, to: to)) }
}
func diffs(startingWith first: E) -> Observable<([Patch<E.Element>])> {
return withDiffs(startingWith: first).map { $0.1 }
}
}
extension ObservableType where E:Collection, E.Iterator.Element: Equatable {
func withDiffs(startingWith first: E) -> Observable<(E, [Patch<E.Element>])> {
return withPrevious(startWith: first)
.map { from, to in (to, from.diff(to).patch(from: from, to: to)) }
}
}
public extension Diff {
/// Generates a patch sequence based on a diff. It is a list of steps to be applied to obtain the `to` collection from the `from` one.
///
/// - Complexity: O(N)
///
/// - Parameters:
/// - from: The source collection (usually the source collecetion of the callee)
/// - to: The target collection (usually the target collecetion of he callee)
/// - Returns: A sequence of steps to obtain `to` collection from the `from` one.
public func patch<T: Collection, U>(from: T, to: T, offset: Int, _ transform: (T.Element) -> U)
-> [Patch<U>] where T.Iterator.Element: Equatable {
return patch(from: from, to: to).map { $0.map(offset: offset, transform) }
}
}
public extension Patch {
public func map<U>(offset: Int, _ transform: (Element) -> U) -> Patch<U> {
switch self {
case let .insertion(index, element):
return .insertion(index: index + offset, element: transform(element))
case let .deletion(index):
return .deletion(index: index + offset)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment