From b6c18e474cc828b079672a849f807e366898a8dc Mon Sep 17 00:00:00 2001 From: Laurence Chen Date: Thu, 5 Mar 2026 21:43:13 +0800 Subject: [PATCH 1/2] Fix replacements mispairing deletions and insertions when second seq is longer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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}] --- src/lambdaisland/deep_diff2/diff_impl.cljc | 16 ++++++++++++---- test/lambdaisland/deep_diff2/diff_test.cljc | 9 +++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/lambdaisland/deep_diff2/diff_impl.cljc b/src/lambdaisland/deep_diff2/diff_impl.cljc index e158c95..68f072b 100644 --- a/src/lambdaisland/deep_diff2/diff_impl.cljc +++ b/src/lambdaisland/deep_diff2/diff_impl.cljc @@ -51,10 +51,18 @@ (dissoc (dec d)) (assoc d (seq (concat (next i) (get ins d)))))) - (recur rep - del - (next del-rest) - ins))) + (if-let [nearest (first (sort (filter #(> % d) (keys ins))))] + (if (and (every? del (range (inc d) (inc nearest))) + (seq (get ins nearest))) + (let [i (get ins nearest)] + (recur (assoc rep d (first i)) + (disj del d) + (next del-rest) + (-> ins + (dissoc nearest) + (assoc d (seq (concat (next i) (get ins d))))))) + (recur rep del (next del-rest) ins)) + (recur rep del (next del-rest) ins)))) [rep del (into {} (remove (comp nil? val)) (shift-insertions ins))]))) diff --git a/test/lambdaisland/deep_diff2/diff_test.cljc b/test/lambdaisland/deep_diff2/diff_test.cljc index 4e0cff2..3c1b726 100644 --- a/test/lambdaisland/deep_diff2/diff_test.cljc +++ b/test/lambdaisland/deep_diff2/diff_test.cljc @@ -66,7 +66,7 @@ (is (= [(diff/->Insertion []) {} (diff/->Insertion [])] (diff/diff [{}] [[] {} []]))) - (is (= [0 (diff/->Deletion 1) (diff/->Mismatch 2 :x) (diff/->Insertion :y) (diff/->Insertion :z)] + (is (= [0 (diff/->Mismatch 1 :x) (diff/->Mismatch 2 :y) (diff/->Insertion :z)] (diff/diff [0 1 2] [0 :x :y :z])))) (testing "sets" @@ -167,7 +167,7 @@ (is (= [#{1 2} {2 [:x :y :z]}] (diff/del+ins [0 1 2] [0 :x :y :z]))) - (is (= [{2 :x} #{1} {2 '(:y :z)}] + (is (= [{1 :x, 2 :y} #{} {2 '(:z)}] (diff/replacements [#{1 2} {2 [:x :y :z]}]))) (is (= [{} #{} {-1 [1], 1 [3], 3 [5]}] @@ -304,6 +304,11 @@ (is (= [:a (diff/->Deletion :b) :c (diff/->Insertion :d)] (diff/diff-seq [:a :b :c] [:a :c :d])))) +(deftest diff-longer-second-seq-test + (testing "when second sequence is longer and has no common elements, replacements are paired correctly" + (is (= [{:a (diff/->Mismatch 1 2)} {:b (diff/->Mismatch 1 2)} (diff/->Insertion {:c 2})] + (diff/diff '({:a 1} {:b 1}) '({:a 2} {:b 2} {:c 2})))))) + (comment (use 'kaocha.repl) From d7163729687c2fd4ea1219827ad862f20f51ec14 Mon Sep 17 00:00:00 2001 From: Laurence Chen Date: Thu, 5 Mar 2026 21:53:45 +0800 Subject: [PATCH 2/2] add CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a7afa5..2c5d574 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ## Fixed +- Fixed Fix replacements mispairing when second sequence is longer - Fixed puget printer for futures ## Changed