やりたいこと
リストの中に入ってる複数の辞書が、キーと値が全て同じものであったら重複として削除したい
結論
unique_everseen
を使用する。
pip install more-itertools
辞書の順番が異なっていたら別物として扱いたい場合
from more_itertools import unique_everseen
# [0]と[3]は区別する
target_list = [
{"item1": "value1", "item4": "value4"},
{"item2": "value2", "item5": "value5"},
{"item3": "value3", "item5": "value5"},
{"item4": "value4", "item1": "value1"},
]
list(unique_everseen(target_list))
辞書の順番が異なっていても、キーと値が同じなら同一として扱いたい場合
from more_itertools import unique_everseen
# [0]と[3]は同じとみなす
target_list = [
{"item1": "value1", "item4": "value4"},
{"item2": "value2", "item5": "value5"},
{"item3": "value3", "item5": "value5"},
{"item4": "value4", "item1": "value1"},
]
list(unique_everseen(target_list, key=lambda dict: frozenset(dict.items())))
補足
このケースにおいて考えられるパターンは以下2パターン。
どちらのケースにおいても、上記の実装は対応可能。
パターン1
単純なdict
target_list = [
{"item1": "value1"},
{"item2": "value2"},
{"item3": "value3"},
{"item1": "value1"},
]
パターン2
dictの中にさらにdictが含まれてるパターン
target_list = [
{
"item1": "value1",
"item2": {
"nest1": "nestValue1",
"nest2": "nestValue2",
}
},
{
"item3": "value3",
"item4": {
"nest1": "nestValue1",
"nest2": "nestValue2",
}
},
{
"item1": "value1",
"item2": {
"nest1": "nestValue1",
"nest2": "nestValue2",
}
},
]
この関数知らなかったので、自作してた。。全然要らなかった。
# 重複する辞書を削除
unique_list = list(
{convert_to_hashable(d): d for d in target_list}.values()
)
def convert_to_hashable(obj: Any) -> Union[tuple, Any]:
"""再帰的に辞書やリストをハッシュ可能な形式に変換する関数
Args:
obj (Any): 辞書やリスト、またはその他の型を受け付けます
Returns:
Union[tuple, Any]: タプルに変換されたハッシュ可能なオブジェクト、または元のオブジェクト
"""
if isinstance(obj, dict):
# 辞書のキーと値をソートしてタプルに変換し、frozendictに変換
# ソートするので順番が異なる辞書も比較可能
return tuple(
(key, convert_to_hashable(value)) for key, value in sorted(obj.items())
)
elif isinstance(obj, list):
# リスト内の要素もハッシュ可能にするため、リストを再起的にタプルに変換
return tuple(convert_to_hashable(item) for item in obj)
return obj