onmyway133/DeepDiff

Example using two String arrays

Closed this issue · 6 comments

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!

@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?

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.

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

@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 onmyway133/blog#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?

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!

@jakunico Glad that it works 👍