i-focus i-focus BB
    • カテゴリ
    • 最近
    • タグ
    • 人気
    • ユーザー
    • グループ
    • 登録
    • ログイン

    今日の学び:集合型に辞書型を入れることはできない

    Python
    python
    1
    2
    322
    もっと見る
    • 古いものから新しい順
    • 新しいものから古い順
    • 最高評価
    返信
    • スレッドとして返信する
    投稿するのにログインして下さい
    このスレッドが削除されました。スレッド管理権を持っているユーザーにしか読めません。
    • i_yamasakiI
      i_yamasaki
      最後に編集した時間i_yamasaki

      myset = {
          {"a": 1},
          {"b": 2}
      }
      # TypeError: unhashable type: 'dict'
      

      辞書型どうしで比較できるんだから集合に入れたときも頑張ってくれたっていいじゃん…

      1 件の返信 最後の返信 返信 引用 0
      • i_yamasakiI
        i_yamasaki
        最後に編集した時間i_yamasaki

        集合型にはミュータブル型(変更不可)しか入れられないのが原因らしい。

        辞書はイミュータブル型(変更可能)だから入らなかったので一度文字列(ミュータブル型)に変換して入れた後にリストに入れれば疑似的に重複を削除できた。

        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}]
        # 同じ内容の場合後に出てきたものが入る
        

        あまり賢い方法には思えないがこれが一番スッキリしていると思う。

        1 件の返信 最後の返信 返信 引用 2
        • First post
          Last post