Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで2つの辞書リストを比較する方法|差分の出力とPandas活用術

この記事では、Pythonで2つの「辞書のリスト」を比較し、両者の差分を出力する方法を解説します。

ここで紹介する比較方法では、辞書内のキーと値の両方が比較対象になります。

また、Pythonで辞書のリスト同士を比較する場合、要素の並び順は結果に影響しません。キーと値の組み合わせが同じであれば、順序が異なっていても等しいものとして扱われます。

Pythonで辞書のリストを比較する基本方法

if __name__ == '__main__':

    list_1 = [
        {'id': '123-abc', 'name': 'Mike', 'age': 40},
        {'name': 'John', 'age': 34, 'id': '123-efg'},
        {'age': 32, 'id': '123-xyz', 'name': 'Aly'}
    ]

    list_2 = [
        {'name': 'Mike', 'id': '123-abc', 'age': 40},
        {'id': '123-efg', 'age': 34, 'name': 'John'},
        {'id': '123-xyz', 'name': 'Aly', 'age': 32}
    ]

    assert [i for i in list_1 if i not in list_2] == []

上記のコードでは、list_1list_2 は等しいと判定されます。つまり、両方のリストに含まれる各辞書が同じ項目(キーと値)を持っているということです。各辞書内での要素の並び順は問われません。

このアプローチのポイントは、リスト内包表記を使って「list_1 のうち list_2 に存在しない要素」を抽出している点です。結果が空リストであれば、2つのリストは一致していることになります。

辞書のリストを比較して差分を出力する

単に一致・不一致を判定するだけでなく、「どの辞書が異なっているのか」を出力することもできます。

例えば、次のように記述します。

if __name__ == '__main__':

    list_1 = [
        {'id': '123-abc', 'name': 'Mike', 'age': 40},
        {'id': '123-efg', 'name': 'John', 'age': 24},
        {'id': '123-xyz', 'name': 'Aly', 'age': 35}
    ]

    list_2 = [
        {'id': '123-abc', 'name': 'Mike', 'age': 40},
        {'id': '123-efg', 'name': 'Jon', 'age': 24},
        {'id': '123-xyz', 'name': 'Aly', 'age': 32}
    ]

    for i in list_1:
        if i not in list_2:
            print(i)

実行結果:

{'id': '123-efg', 'name': 'John', 'age': 24}
{'id': '123-xyz', 'name': 'Aly', 'age': 35}

この例では、list_1 に含まれていて list_2 には存在しない辞書だけが出力されます。'name''age' の値が少しでも違えば、別の辞書として扱われる点に注意してください。

関数化して再利用しやすくする

同じ処理を関数としてまとめると、次のように書けます。

def compare_two_lists(list1: list, list2: list) -> bool:
    """
    2つのリストを比較し、差分をログに出力する。
    :param list1: 1つ目のリスト
    :param list2: 2つ目のリスト
    :return:      差分がない場合は True
    """
    diff = [i for i in list1 + list2 if i not in list1 or i not in list2]
    result = len(diff) == 0
    if not result:
        print(f'{len(diff)}件の差分があります:\n{diff[:5]}')
    return result

この関数は、両方のリストを結合した上で「どちらか一方にしか存在しない要素」を差分として検出します。差分がある場合は、その件数と内容(最大5件)を出力し、戻り値として一致の可否を bool 型で返します。

Pandas DataFrameを使って2つのリストを比較する

より大規模なデータや複雑な条件で比較したい場合は、PandasのDataFrameを活用すると便利です。以下のコードは、2つのリストをDataFrameに変換して差分を求める例です。

from pandas import DataFrame
import pandas as pd

def compare_two_lists(list1: list, list2: list) -> bool:
    """
    2つのリストを比較し、差分をログに出力する。
    :param list1: 1つ目のリスト
    :param list2: 2つ目のリスト
    :return:      差分がない場合は True
    """
    df1 = pd.DataFrame(list1)
    df2 = pd.DataFrame(list2)
    diff = dataframe_difference(df1, df2)
    result = len(diff) == 0
    if not result:
        print(f'{len(diff)}件の差分があります:\n{diff.head()}')
    return result

def dataframe_difference(df1: DataFrame, df2: DataFrame) -> DataFrame:
    """
    2つのDataFrame間で異なる行を検出する。
    :param df1: 1つ目のDataFrame
    :param df2: 2つ目のDataFrame
    :return:    差分となる行のみを含むDataFrame
    """
    comparison_df = df1.merge(df2, indicator=True, how='outer')
    diff_df = comparison_df[comparison_df['_merge'] != 'both']
    return diff_df

この方法では、merge() メソッドに indicator=True を指定することで、各行が「片方のDataFrameにのみ存在するのか」「両方に存在するのか」を示す _merge 列が自動的に追加されます。この列が 'both' 以外の行、すなわちどちらかにしか存在しない行を抽出すれば、それが2つのリスト間の差分となります。

データ量が多い場合や、差分行の一覧を表形式で確認したい場合には、このPandasを使った手法が特に有効です。

  1. Pythonで2つのリストの要素を加算する方法【append・map・zip】

    Pythonでは、2つのリストを「足し合わせる」ことで、両方のリストの要素を含む新しいリストを作成できます。ここでいう「追加」とは、リスト同士を単純に連結するのではなく、同じインデックス位置にある要素同士を加算することを指します。本記事では、代表的な3つの手法をコード例とともに解説します。なお、いずれの方法でも2つのリストは同じ長さである必要がある点に注意してください。1. append()を使う方法append()メソッドを使うと、片方のリストの要素を別のリストへ追加できます。ここでは空の新しいリストを用意し、forループで各インデックスの要素を加算しながら順に追加していきます。コード例Li

  2. Pythonで2つの辞書を1つの式でマージする方法

    Pythonで2つの辞書を1つに結合(マージ)したい場面はよくあります。ここでは、代表的な2つの方法をサンプルコード付きでわかりやすく解説します。 update()メソッドを使う方法 組み込みの辞書(dict)クラスにはupdate()メソッドが用意されています。このメソッドは、引数として渡した辞書オブジェクトの要素を、呼び出し元の辞書オブジェクトに統合します。なお、元の辞書そのものが更新される点に注意してください。 >>> a = {1:a, 2:b, 3:c} >>> b = {x:1, y:2, z:3} >>> a.updat