JSON Diffでの配列比較
JSON diffツールが配列比較をどのように処理するかを学びます。インデックスベースとIDベースのdiff、要素の追加・削除・並べ替え検出について解説します。
Structural Diffs
詳細な説明
配列はJSON diffアルゴリズムにとって最も難しいデータ構造です。キーが自然な識別子を提供するオブジェクトとは異なり、配列要素はその位置(インデックス)でのみ識別されるためです。異なるdiff戦略は大幅に異なる結果を生成します。
インデックスベースの比較(ナイーブ):
最もシンプルなアプローチは、同じインデックスの要素を比較します。配列が伸縮した場合、末尾の要素は追加または削除として報告されます:
// 変更前
["apple", "banana", "cherry"]
// 変更後
["apple", "blueberry", "banana", "cherry"]
インデックスベースのdiffの報告:
- インデックス1:
"banana"を"blueberry"に変更 - インデックス2:
"cherry"を"banana"に変更 - インデックス3:
"cherry"を追加
これは技術的には正しいですが誤解を招きます。実際の変更はインデックス1に "blueberry" を挿入したことです。
LCSベースの比較(スマート):
より洗練されたアルゴリズムは、**最長共通部分列(LCS)**アルゴリズム(git diff がテキスト行に使用するものと同様)を使用して、最適な編集操作セットを見つけます。LCSは正確に以下を特定します:
- インデックス1:
"blueberry"を挿入
IDベースの比較(配列内のオブジェクト):
配列がオブジェクトを含む場合、多くのdiffツールではIDキー(id など)を指定して、位置に関係なく2つの配列間で要素をマッチングできます:
// 変更前
[
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
// 変更後
[
{ "id": 2, "name": "Robert" },
{ "id": 1, "name": "Alice" }
]
id フィールドでIDベースのdiffを行うと、アルゴリズムはBobの名前がRobertに変更され、順序が入れ替わったことを正しく報告します(両方の要素が完全に置換されたと報告するのではなく)。
ベストプラクティス:
- 可能な限り、オブジェクトの配列にはIDベースのdiffを使用してください。
- IDキーのない大きな配列はノイズの多いdiffを生成することに注意してください。
- 順序が重要でない場合、偽陽性を減らすために比較前に配列をソートすることを検討してください。
ユースケース
カタログ更新後に商品リストを返すAPIレスポンスの2つのバージョンを比較し、どのアイテムが追加、削除、またはプロパティが変更されたかを特定する。