集合型にはミュータブル型(変更不可)しか入れられないのが原因らしい。
辞書はイミュータブル型(変更可能)だから入らなかったので一度文字列(ミュータブル型)に変換して入れた後にリストに入れれば疑似的に重複を削除できた。
import json
dlist = [
{"a": 1},
{"a": 1}, # 同じ値
{"b": 2},
]
dlist_new = [json.loads(d_str) for d_str in {json.dumps(d_dict) for d_dict in dlist}]
# dlist_new = [{"a": 1}, {"b": 2}]
# dlist_newの中身は順不同
ミュータブル型に変換するのであれば辞書のキーにしてしまい値だけ取り出す方法でもできることに気が付いた。こちらのほうがすっきりしていて見やすい気がする。また、愚直に集合型を使用しないので中身が元のリストの出現順になる。
import json
dlist = [
{"a": 1},
{"a": 1}, # 同じ値
{"b": 2},
]
dlist_new = list({json.dumps(d): d for d in dlist}.values())
print(dlist_new)
# dlist_new = [{"a": 1}, {"b": 2}]
辞書の要素の順がすべて同じであると保証されている場合はこれでも良いが、よく考えると要素の出現順が違うとこの方法だとうまくいかないことに気が付いてしまった。
import json
dlist = [
{"c": 3, "a": 1},
{"a": 1, "c": 3}, # 同じ値、ただし順番は違う
{"b": 2, "c": 3},
]
dlist_new1 = [json.loads(d_str) for d_str in {json.dumps(d_dict) for d_dict in dlist}]
# [{'c': 3, 'a': 1}, {'a': 1, 'c': 3}, {'b': 2, 'c': 3}]
# 重複削除失敗
dlist_new2 = list({json.dumps(d): d for d in dlist}.values())
# [{'c': 3, 'a': 1}, {'a': 1, 'c': 3}, {'b': 2, 'c': 3}]
# 重複削除失敗
辞書の順をソートしても良いが、ネストが深い場合にどうにもならないので比較するしかなさそう。すでに出てきた辞書を追加するリストを使う方法が最初に浮かんだ。
dlist = [
{"c": 3, "a": 1},
{"a": 1, "c": 3}, # 同じ値、ただし順番は違う
{"b": 2, "c": 3},
]
dlist_new = []
for d in dlist:
if d not in dlist_new:
dlist_new.append(d)
# dlist_new = [{'c': 3, 'a': 1}, {'b': 2, 'c': 3}]
ただどうしてもワンライナーで書きたかったので考えていたところ、dlist内の比較結果が同じもので作成したリストを文字列に変換し、それをキーにしてリスト内の比較結果が同じものを紐づける方法を思いついた。
import json
dlist = [
{"c": 3, "a": 1},
{"a": 1, "c": 3}, # 同じ値、ただし順番は違う
{"b": 2, "c": 3},
]
dlist_new = list({json.dumps([_d for _d in dlist if d == _d]): d for d in dlist}.values())
# [{'a': 1, 'c': 3}, {'b': 2, 'c': 3}]
# 同じ内容の場合後に出てきたものが入る
あまり賢い方法には思えないがこれが一番スッキリしていると思う。