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つのバージョンを比較し、どのアイテムが追加、削除、またはプロパティが変更されたかを特定する。

試してみる — JSON Diff

フルツールを開く