• This repository has been archived on 05/Dec/2022
  • Stars
    star
    2,049
  • Rank 22,360 (Top 0.5 %)
  • Language
    Swift
  • License
    Other
  • Created almost 7 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🦀Amazingly incredible extraordinary lightning fast diffing in Swift

DeepDiff

❤️ Support my apps ❤️

❤️❤️😇😍🤘❤️❤️

CI Status Version Carthage Compatible License Platform Swift

DeepDiff tells the difference between 2 collections and the changes as edit steps. It also supports Texture, see Texture example

Usage

Basic

The result of diff is an array of changes, which is [Change]. A Change can be

  • .insert: The item was inserted at an index
  • .delete: The item was deleted from an index
  • .replace: The item at this index was replaced by another item
  • .move: The same item has moved from this index to another index

By default, there is no .move. But since .move is just .delete followed by .insert of the same item, it can be reduced by specifying reduceMove to true.

Here are some examples

let old = Array("abc")
let new = Array("bcd")
let changes = diff(old: old, new: new)

// Delete "a" at index 0
// Insert "d" at index 2
let old = Array("abcd")
let new = Array("adbc")
let changes = diff(old: old, new: new)

// Move "d" from index 3 to index 1
let old = [
  User(id: 1, name: "Captain America"),
  User(id: 2, name: "Captain Marvel"),
  User(id: 3, name: "Thor"),
]

let new = [
  User(id: 1, name: "Captain America"),
  User(id: 2, name: "The Binary"),
  User(id: 3, name: "Thor"),
]

let changes = diff(old: old, new: new)

// Replace user "Captain Marvel" with user "The Binary" at index 1

DiffAware protocol

Model must conform to DiffAware protocol for DeepDiff to work. An model needs to be uniquely identified via diffId to tell if there have been any insertions or deletions. In case of same diffId, compareContent is used to check if any properties have changed, this is for replacement changes.

public protocol DiffAware {
  associatedtype DiffId: Hashable

  var diffId: DiffId { get }
  static func compareContent(_ a: Self, _ b: Self) -> Bool
}

Some primitive types like String, Int, Character already conform to DiffAware

Animate UITableView and UICollectionView

Changes to DataSource can be animated by using batch update, as guided in Batch Insertion, Deletion, and Reloading of Rows and Sections

Since Change returned by DeepDiff follows the way batch update works, animating DataSource changes is easy.

For safety, update your data source model inside updateData to ensure synchrony inside performBatchUpdates

let oldItems = items
let newItems = DataSet.generateNewItems()
let changes = diff(old: oldItems, new: newItems)

collectionView.reload(changes: changes, section: 2, updateData: { 
  self.items = newItems
})

Take a look at Demo where changes are made via random number of items, and the items are shuffled.

How does it work

If you recall from school, there is Levenshtein distance which counts the minimum edit distance to go from one string to another.

Based on that, the first version of DeepDiff implements Wagner–Fischer, which uses dynamic programming to compute the edit steps between 2 strings of characters. DeepDiff generalizes this to make it work for any collection.

Some optimisations made

  • Check empty old or new collection to return early
  • Use diffId to quickly check that 2 items are not equal
  • Follow "We can adapt the algorithm to use less space, O(m) instead of O(mn), since it only requires that the previous row and current row be stored at any one time." to use 2 rows, instead of matrix to reduce memory storage.

The performance greatly depends on the number of items, the changes and the complexity of the equal function.

Wagner–Fischer algorithm has O(mn) complexity, so it should be used for collection with < 100 items.

Heckel

The current version of DeepDiff uses Heckel algorithm as described in A technique for isolating differences between files. It works on 2 observations about line occurrences and counters. The result is a bit lengthy compared to the first version, but it runs in linear time.

Thanks to

More

There are other algorithms that are interesting

Benchmarks

Benchmarking is done on real device iPhone 6, with random items made of UUID strings (36 characters including hyphens), just to make comparisons more difficult.

You can take a look at the code Benchmark. Test is inspired from DiffUtil

Among different frameworks

Here are several popular diffing frameworks to compare

💪 From 2000 items to 2100 items (100 deletions, 200 insertions)

let (old, new) = generate(count: 2000, removeRange: 100..<200, addRange: 1000..<1200)

benchmark(name: "DeepDiff", closure: {
  _ = DeepDiff.diff(old: old, new: new)
})

benchmark(name: "Dwifft", closure: {
  _ = Dwifft.diff(old, new)
})

benchmark(name: "Changeset", closure: {
  _ = Changeset.edits(from: old, to: new)
})

benchmark(name: "Differ", closure: {
  _ = old.diffTraces(to: new)
})

benchmark(name: "ListDiff", closure: {
  _ = ListDiff.List.diffing(oldArray: old, newArray: new)
})

Result

DeepDiff: 0.0450611114501953s
Differ: 0.199673891067505s
Dwifft: 149.603884935379s
Changeset: 77.5895738601685s
ListDiff: 0.105544805526733s

Increasing complexity

Here is how DeepDiff handles large number of items and changes

💪 From 10000 items to 11000 items (1000 deletions, 2000 insertions)

DeepDiff: 0.233131170272827s

💪 From 20000 items to 22000 items (2000 deletions, 4000 insertions)

DeepDiff: 0.453393936157227s

💪 From 50000 items to 55000 items (5000 deletions, 10000 insertions)

DeepDiff: 1.04128122329712s

💪 From 100000 items to 1000000 items

Are you sure?

Installation

CocoaPods

Add the following to your Podfile

pod 'DeepDiff'

Carthage

Add the following to your Cartfile

github "onmyway133/DeepDiff"

Swift Package Manager

Add the following to your Package.swift file

.package(url: "https://github.com/onmyway133/DeepDiff.git", .upToNextMajor(from: "2.3.0"))

DeepDiff can also be installed manually. Just download and drop Sources folders in your project.

Author

Khoa Pham, [email protected]

Contributing

We would love you to contribute to DeepDiff, check the CONTRIBUTING file for more info.

License

DeepDiff is available under the MIT license. See the LICENSE file for more info.

More Repositories

1

awesome-ios-animation

☔ A collection of iOS animation repos
5,305
star
2

awesome-ios-architecture

🏯 Better ways to structure iOS apps
5,056
star
3

PushNotifications

🐉 A macOS, Linux, Windows app to test push notifications on iOS and Android
JavaScript
2,230
star
4

IconGenerator

🍱 A macOS app to generate app icons
JavaScript
1,403
star
5

RoughSwift

🎃 Create hand-drawn, sketchy, comic shape in Swift
Swift
1,104
star
6

FinderGo

🐢 Open terminal quickly from Finder
Swift
1,084
star
7

Snowflake

❄️ SVG in Swift
Swift
956
star
8

GifCapture

🏇 Gif capture app for macOS
Swift
916
star
9

awesome-machine-learning

🎰 A curated list of machine learning resources, preferably CoreML
794
star
10

Swiftlane

🚀 Build utilities in pure Swift
Swift
692
star
11

blog

🍁 What you don't know is what you haven't learned
666
star
12

awesome-swiftui

🌮 Awesome resources, articles, libraries about SwiftUI
642
star
13

EasyConfetti

🎊 Fancy confetti effects in Swift
Swift
561
star
14

XcodeWay

⛵ An Xcode Source Editor Extension that helps navigating to many places easier
Swift
550
star
15

Smile

😄 Emoji in Swift
Swift
512
star
16

EasyAnchor

⚓️ Declarative, extensible, powerful Auto Layout
Swift
455
star
17

EasyStash

🗳Easy data persistence in Swift
Swift
377
star
18

Scale

🎏 Unit converter in Swift
Swift
323
star
19

EasyDropdown

💧 Fantastic dropdown in Swift
Swift
309
star
20

XcodeColorSense2

🍉 An Xcode source editor extension that shows hex color info
Swift
285
star
21

Arcane

🔱 CommonCrypto in Swift, and more
Swift
283
star
22

awesome-android-animation

💦 A collection of Android animation repos
Java
253
star
23

EasyTheme

👕👚 Theme management in Swift
Swift
241
star
24

awesome-voip

🤙Learning VoIP, RTP, pjsip and SIP
237
star
25

SwiftHash

🍕 MD5 in pure Swift
Swift
215
star
26

EasyClosure

🍩 Unified communication patterns with easy closure in Swift
Swift
201
star
27

Github.swift

:octocat: Unofficial GitHub API client in Swift
Swift
186
star
28

emoji

❤️ List of emojis
Swift
163
star
29

SwiftSnippets

🍮 A collection of Swift snippets to be used in Xcode
Shell
162
star
30

Wave

🌊 Declarative chainable animations in Swift
Swift
127
star
31

awesome-online-earning

💰Ways to earn extra
124
star
32

Spek

🎏 Function builder BDD testing framework in Swift
Swift
122
star
33

FontAwesomeSwiftUI

Easy to use FontAwesome 5 in SwiftUI
Swift
97
star
34

Recipes

🍣Making Recipes iOS app
Swift
91
star
35

MathSolver

⌨️Camera calculator with Vision
Swift
87
star
36

XcodeColorSense

🎈 An Xcode plugin that makes working with color easier
Swift
77
star
37

Micro

🏎Fast diffing and type safe SwiftUI style data source for UICollectionView
Swift
76
star
38

Omnia

🗿 Everything your projects need to know
Swift
62
star
39

notes

📔 Issues and solutions I found during development, mostly iOS
62
star
40

Sketch-Action

🔎 A Sketch plugin to simulate Spotlight
Objective-C
59
star
41

MainThreadGuard

💂‍♂️ Tracking UIKit access on main thread
Swift
58
star
42

EasyFake

🤹‍♀️ Fake data generation in Swift
JavaScript
57
star
43

Reindeers

❄️ XML and HTML parser in Swift
Swift
55
star
44

awesome-git-commands

🍴 Indispensable git commands for everyday use
55
star
45

RxLifeCycle

🐹 Easy life cycle observation
Swift
53
star
46

Upstream

⛲️ Adapted Data Source in Swift and a little bit more
Swift
53
star
47

BigBigNumbers

🔢Say the number out loud
Swift
49
star
48

GifMagic

💈 Gif maker and extractor in Swift
Swift
48
star
49

awesome-android-architecture

🏰 Better ways to structure Android apps
45
star
50

AppStoreConnect

🍎 Interact with AppStoreConnect
Swift
45
star
51

TestTarget

🐳 Notes on configuring test targets
Swift
44
star
52

PhotoFeed

🛵 Instagram in Swift 4
Swift
43
star
53

awesome-conference-videos

🎸 Conference videos. Visit http://learntalks.com/
40
star
54

CollectionUpdateExample

🛶 Demo batch update in UITableView and UICollectionView
Swift
38
star
55

Construction

👷 The many ways to construct and configure your entity
Swift
34
star
56

PastePal

PastePal is the best universal clipboard manager for Mac, iPhone and iPad.
31
star
57

github-extended

:octocat: A Chrome extension to discover more repositories
JavaScript
30
star
58

EasyNetworking

🛰Easy networking with async/await
Swift
28
star
59

Runtime-Headers

💿 iOS, macOS runtime headers
Objective-C
28
star
60

UsingPlayground

👶 Demo how to use Playground
Swift
26
star
61

EasySwiftUI

🍰 Extra sugar for SwiftUI
Swift
25
star
62

Farge

🎈Tell the name of hex color
Swift
24
star
63

Avengers

👾Demo how to use CoreML with IBM Watson, Azure Custom Vision, Turi Create
Swift
21
star
64

ISO8601

🎗 Super lightweight ISO8601 Date Formatter in Swift
Swift
21
star
65

SlidingMenu

🎿 Demo how to create sliding menu on Android
Java
20
star
66

Paramount

🗼 Like Flipboard FLEX, but allows custom action
Swift
20
star
67

Codelime

Codelime is a powerful code snippet manager with many dev tools for iOS development.
19
star
68

DynamicTableViewCellHeight

🍟 Demo how to use Autolayout to make varying row height
Objective-C
18
star
69

github-chat

💬 A Chrome extension to enable chat within GitHub
JavaScript
18
star
70

Resolver

🎊 A simple resolver in Swift
Swift
15
star
71

archives

🚣 Only deliberate practice will make you better
Objective-C
14
star
72

ParticlePlayground

🎊 A Swift playground to play with CAEmitterLayer
Swift
14
star
73

json_resolve

🐰Easy resolving deep json using keypath in Dart
Dart
12
star
74

Then

🏃 Promise A+ in Swift
Swift
11
star
75

LighterAppDelegate

🎣 Lighter AppDelegate by dispatching events
Swift
10
star
76

Xkcd

🦄 Simple Xkcd iOS app
Swift
8
star
77

Border

📐 Make border for all views
Swift
8
star
78

Xmas

🎅 🎄 ⛄ Xmas plugin for Xcode
Objective-C
7
star
79

github-changelogs-maker

🍻 Generate changelogs between 2 latest releases
JavaScript
7
star
80

linphone-iphone

Forked from linphone.org
Objective-C
7
star
81

EasyTracker

🕵️ Trackers in Swift
Swift
6
star
82

FantasticDisplay

🎢 Fantastic HUD and toast in Swift
Swift
6
star
83

ComputerScienceSwift

👨‍💻 Practice computer science in Swift
Swift
6
star
84

PushHero

Push Hero is a native macOS application written in pure Swift that allows us to easily test push notifications
6
star
85

onmyway133

What you don't know is what you haven't learned
5
star
86

Minion

🐝 Working with Xcode plugins
Swift
5
star
87

SketchHeaders

💿 Headers from Sketch
Objective-C
4
star
88

homebrew-formulae

🚗 Homebrew formulae
Ruby
3
star
89

DarkSide

🌌 My dark theme based on Atom One Dark
Shell
3
star
90

chat_webrtc

⌨️ Simple chat application using Node.js and WebRTC Data Channel
JavaScript
3
star
91

slackbot-yoda

💍 Slackbot Yoda
JavaScript
2
star
92

onmyway133.github.io

Showcase
HTML
2
star
93

rtpproxy

🥂 Forked from http://www.rtpproxy.org/ with IP handover support
C
2
star
94

android-architecture-components-kotlin

🥋 Samples for Android Architecture Components in Kotlin
Kotlin
2
star
95

traffic_simulator

🚗 Traffic simulator using enchant.js
JavaScript
2
star
96

Shipmunk

Search, bookmark and track keyword rating for your favorite apps
2
star
97

Dust

🚀 Unofficial, simple push notification
Swift
1
star
98

MarqueeTextBlock

🌴 How to make marquee TextBlock on Windows Phone
C#
1
star