All Projects → onmyway133 → Deepdiff

onmyway133 / Deepdiff

Licence: other
🦀Amazingly incredible extraordinary lightning fast diffing in Swift

Programming Languages

swift
15916 projects
ruby
36898 projects - #4 most used programming language
objective c
16641 projects - #2 most used programming language

Projects that are alternatives of or similar to Deepdiff

Westore
更好的小程序项目架构
Stars: ✭ 3,897 (+95.34%)
Mutual labels:  update, diff
BAT FFMPEG
Batch script files for FFMPEG (Microsoft Windows and DOS, OS/2 🦄)
Stars: ✭ 104 (-94.79%)
Mutual labels:  collection, batch
Hdiffpatch
a C\C++ library and command-line tools for Diff & Patch between binary files or directories(folder); cross-platform; run fast; create small delta/differential; support large files and limit memory requires when diff & patch.
Stars: ✭ 459 (-76.99%)
Mutual labels:  update, diff
langx-java
Java tools, helper, common utilities. A replacement of guava, apache-commons, hutool
Stars: ✭ 50 (-97.49%)
Mutual labels:  diff, collection
Apkdiffpatch
a C++ library and command-line tools for Zip(Jar,Apk) file Diff & Patch; create minimal delta/differential; support Jar sign(apk v1 sign) & apk v2,v3 sign .
Stars: ✭ 121 (-93.93%)
Mutual labels:  update, diff
Bodywork Core
Deploy machine learning projects developed in Python, to Kubernetes. Accelerated MLOps 🚀
Stars: ✭ 145 (-92.73%)
Mutual labels:  batch
Awesome Doctrine
A collection of useful Doctrine snippets.
Stars: ✭ 147 (-92.63%)
Mutual labels:  collection
Awesome Bioinformatics Benchmarks
A curated list of bioinformatics bench-marking papers and resources.
Stars: ✭ 142 (-92.88%)
Mutual labels:  collection
Awesome Testflight Link
Collection of Testflight public app link
Stars: ✭ 139 (-93.03%)
Mutual labels:  collection
Composer Lock Diff
See what has changed after a composer update
Stars: ✭ 154 (-92.28%)
Mutual labels:  diff
Awesome Cae
A curated list of awesome CAE frameworks, libraries and software.
Stars: ✭ 148 (-92.58%)
Mutual labels:  collection
Php Htmldiff
A library for comparing two HTML files/snippets and highlighting the differences using simple HTML. Includes support for comparing complex lists and tables
Stars: ✭ 145 (-92.73%)
Mutual labels:  diff
Twcommunities
整理與蒐集台灣社群活動投影片
Stars: ✭ 145 (-92.73%)
Mutual labels:  collection
Efcore.bulkextensions
Entity Framework Core Bulk Batch Extensions for Insert Update Delete Read (CRUD), Truncate and SaveChanges operations on SQL Server, PostgreSQL, SQLite
Stars: ✭ 2,295 (+15.04%)
Mutual labels:  batch
Update
清晰灵活简单易用的应用更新库
Stars: ✭ 1,739 (-12.83%)
Mutual labels:  update
Easysequence
EasySequence is a powerful fundamental library to process sequcence type, such as array, set, dictionary. All type object which conforms to NSFastEnumeration protocol can be initialzed to an EZSequence instance, then you can operation with them. Finally, you can transfer them back to the original type.
Stars: ✭ 150 (-92.48%)
Mutual labels:  collection
Sitediff
SiteDiff makes it easy to see differences between two versions of a website.
Stars: ✭ 139 (-93.03%)
Mutual labels:  diff
Awesome Ruby
💎 A collection of awesome Ruby libraries, tools, frameworks and software
Stars: ✭ 11,838 (+493.38%)
Mutual labels:  collection
Dwifft
Swift Diff
Stars: ✭ 1,822 (-8.67%)
Mutual labels:  diff
Tqsdk Python
天勤量化开发包, 期货量化, 实时行情/历史数据/实盘交易
Stars: ✭ 2,213 (+10.93%)
Mutual labels:  diff

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

Wagner–Fischer

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.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].