onmyway133 / DeepDiff

🦀Amazingly incredible extraordinary lightning fast diffing in Swift
https://onmyway133.com/apps/
Other
2.05k stars 143 forks source link

Example using two String arrays #43

Closed jakunico closed 5 years ago

jakunico commented 5 years ago

Hey! We're trying to use DeepDiff with UIStackView which does not offer batch updates support as UITableView and UICollectionView. This means that when we get an insert we insert a new arrangedSubview, when we get a delete we delete it, and so on.

We narrowed down the problem to the following example:

var old = ["Category3", "Category2", "Category4", "Category5", "Category1"]
let new = ["Category1", "Category2", "Category3", "Category4", "Category5"]

let algorithm = WagnerFischer<String>()
let changes = algorithm.diff(old: old, new: new)

changes.forEach { change in
    switch change {
    case .insert(let info):
        old.insert(info.item, at: info.index)
    case .delete(let info):
        old.remove(at: info.index)
    case .move(let info):
        old.remove(at: info.fromIndex)
        old.insert(info.item, at: info.toIndex)
    case .replace(let info):
        old.remove(at: info.index)
        old.insert(info.newItem, at: info.index)
    }
}

print(old) // ["Category1", "Category2", "Category3", "Category4", "Category1"]
(lldb) po changes
▿ replace : Replace<String>
  - oldItem : "Category3"
  - newItem : "Category1"
  - index : 0
▿ insert : Insert<String>
  - item : "Category3"
  - index : 2
▿ delete : Delete<String>
  - item : "Category1"
  - index : 4

As you can see the output is not correct. We're probably missing something at some point but cannot identify where.

Let us know. Thanks!

onmyway133 commented 5 years ago

@jakunico Hi, the changes is a changeset of how to transform old to new, you should not apply changes to old again. It is intended to be fed into UITableView or UICollectionView. What do you want to achieve?

jakunico commented 5 years ago

Hey @onmyway133, we have a UIStackView which shows a list of categories represented by [String].

We want to smartly update its arrangedSubviews by inserting/removing/moving/replacing categories as category updates are received from our backend. To do this we iterate over the changes and update the stack view change by change. For instance, if change is to insert a new category into the stack, we would create a label and insert it. If change is to remove a label at a certain index, we would get the label at that index and remove it.

Let us know if that's clear.

jakunico commented 5 years ago

@onmyway133 any thoughts on this? Let us know if our problem is still not clear.

onmyway133 commented 5 years ago

@jakunico Hi, I see what you want to achieve here, and interesting use case with UIStackView 👍 About the changes that you said is not correct

(lldb) po changes
▿ replace : Replace<String>
  - oldItem : "Category3"
  - newItem : "Category1"
  - index : 0
▿ insert : Insert<String>
  - item : "Category3"
  - index : 2
▿ delete : Delete<String>
  - item : "Category1"
  - index : 4

Do you mean delete "Category1" should occur on index 5? If this is your concern, then this diffing works a bit in similar way to how UICollectionView/UITableView works, you can read in my post here https://github.com/onmyway133/blog/issues/119

Deletes are processed before inserts in batch operations. This means the indexes for the deletions are processed relative to the indexes of the collection view’s state before the batch operation, and the indexes for the insertions are processed relative to the indexes of the state after all the deletions in the batch operation.

I haven't looked into UIStackView yet, but can you try with deletions first?

jakunico commented 5 years ago

Hey! Processing deletion before insertion worked in this case 👍 We already replaced the UIStackView with UICollectionView so this we don't need anymore. Closing, thank you!

onmyway133 commented 5 years ago

@jakunico Glad that it works 👍