Skip to content

Commit b6c18e4

Browse files
committed
Fix replacements mispairing deletions and insertions when second seq is longer
When deep-diff places all insertions at the last index of the original sequence, early deletions couldn't find their matching insertion because replacements only checked positions d and d-1. Add a fallback that finds the nearest insertion key > d, but only when all indices between d and that key are also being deleted (no surviving elements in between). This ensures correct positional pairing without false matches. Example: (diff '({:a 1} {:b 1}) '({:a 2} {:b 2} {:c 2})) Before (wrong): [Deletion{:a 1} {Deletion{:b} 1, Insertion{:a} 2} Insertion{:b 2} Insertion{:c 2}] After (correct): [{:a Mismatch{1→2}} {:b Mismatch{1→2}} Insertion{:c 2}]
1 parent cb8385f commit b6c18e4

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

src/lambdaisland/deep_diff2/diff_impl.cljc

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,18 @@
5151
(dissoc (dec d))
5252
(assoc d (seq (concat (next i)
5353
(get ins d))))))
54-
(recur rep
55-
del
56-
(next del-rest)
57-
ins)))
54+
(if-let [nearest (first (sort (filter #(> % d) (keys ins))))]
55+
(if (and (every? del (range (inc d) (inc nearest)))
56+
(seq (get ins nearest)))
57+
(let [i (get ins nearest)]
58+
(recur (assoc rep d (first i))
59+
(disj del d)
60+
(next del-rest)
61+
(-> ins
62+
(dissoc nearest)
63+
(assoc d (seq (concat (next i) (get ins d)))))))
64+
(recur rep del (next del-rest) ins))
65+
(recur rep del (next del-rest) ins))))
5866
[rep del (into {}
5967
(remove (comp nil? val))
6068
(shift-insertions ins))])))

test/lambdaisland/deep_diff2/diff_test.cljc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
(is (= [(diff/->Insertion []) {} (diff/->Insertion [])]
6767
(diff/diff [{}] [[] {} []])))
6868

69-
(is (= [0 (diff/->Deletion 1) (diff/->Mismatch 2 :x) (diff/->Insertion :y) (diff/->Insertion :z)]
69+
(is (= [0 (diff/->Mismatch 1 :x) (diff/->Mismatch 2 :y) (diff/->Insertion :z)]
7070
(diff/diff [0 1 2] [0 :x :y :z]))))
7171

7272
(testing "sets"
@@ -167,7 +167,7 @@
167167
(is (= [#{1 2} {2 [:x :y :z]}]
168168
(diff/del+ins [0 1 2] [0 :x :y :z])))
169169

170-
(is (= [{2 :x} #{1} {2 '(:y :z)}]
170+
(is (= [{1 :x, 2 :y} #{} {2 '(:z)}]
171171
(diff/replacements [#{1 2} {2 [:x :y :z]}])))
172172

173173
(is (= [{} #{} {-1 [1], 1 [3], 3 [5]}]
@@ -304,6 +304,11 @@
304304
(is (= [:a (diff/->Deletion :b) :c (diff/->Insertion :d)]
305305
(diff/diff-seq [:a :b :c] [:a :c :d]))))
306306

307+
(deftest diff-longer-second-seq-test
308+
(testing "when second sequence is longer and has no common elements, replacements are paired correctly"
309+
(is (= [{:a (diff/->Mismatch 1 2)} {:b (diff/->Mismatch 1 2)} (diff/->Insertion {:c 2})]
310+
(diff/diff '({:a 1} {:b 1}) '({:a 2} {:b 2} {:c 2}))))))
311+
307312

308313
(comment
309314
(use 'kaocha.repl)

0 commit comments

Comments
 (0)