🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

4回答

1051閲覧

複数リストから共通の値を取り出したい

mi_o6

総合スコア0

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2021/01/16 09:16

前提・実現したいこと

pythonのリスト・辞書を学習しています。
2つのリストから共通の要素(a)を取り出すためのコードを書いていますが、エラーが出てしまったのでご教授ください。

該当のソースコード

aaa = ["a", "b"] bbb = [ {"ss":"a", "lll":["c", "a"]}, {"ss":"n", "lll":["k"]} ] # bbbからlllを取得しcccに代入 ccc = [d.get("lll") for d in bbb] rst = set(aaa) & set(ccc) print(rst)

発生している問題・エラーメッセージ

unhashable type: 'list'

ハッシュ関数について調べてみましたが、ハッキリと理解できずにいます。
今回の場合で解釈すると、2つの異なる型だからエラーが出ているのでしょうか?

rst = set(aaa)はリスト set(ccc)は辞書の中のリスト

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

set とは、ユニークな値(重複しない値)の集合体で、set に含まれる値は、hashable(ハッシュ可能)である必要があります。

あなたの書いた例で言うと、ccc に入る内は [["c", "a"], ["k"]] になりますが、

python

1[ 2 ["c", "a"] , # list 3 ["k"] # list 4]

リスト内にリストが含まれている状態ですよね。これをsetに変換しようとして、エラーになっている状況だと思います。

list はhashableではないから、という事ですが、そもそもハッシュとは「その値を一意に特定するための値」なので、生存期間中に変わらないオブジェクトである必要があります。listは他の値や参照を入れるための入れ物なので、中身が追加されたり変更されたりするものであり、ハッシュを持ちません。

※ハッシュ可能なクラスには 「_hash_」というメソッドが定義されますが(または自分で定義しますが)、
listクラスの_hash_はNoneです。

リストが入れ子になっているのを、いったんフラットにしてからやると上手くいきます。

python

1import itertools 2 3ccc = [d.get("lll") for d in bbb] 4ccc = list(itertools.chain.from_iterable(ccc)) # ※ 5rst = set(aaa) & set(ccc) 6print(rst) 7

※[["c", "a"], ["k"]] を、["c","a","k"]にしてます

投稿2021/01/16 09:52

umau

総合スコア831

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

失礼いたしました。

引用元:
【Pythonエラー解決】「TypeError: unhashable type: xxx」

~~ > 自分で定義したオブジェクトを辞書のkeyに設定しようとすると、ハッシュ化できないからエラーになる。 ~~
~~ > intやstrのようなハッシュ化可能なオブジェクトをkeyに設定する必要がある。~~

⇒ 辞書のkeyがlist型だとハッシュ化できないため、数値(int)やstr(文字列)を辞書のkeyに設定する

投稿2021/01/16 09:30

編集2021/01/16 10:59
_whitecat_22

総合スコア1305

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

hashableの問題は、==の問題と並んで、pythonのダークマターです。

一応説明を書いておきますが、umauさんが書かれているように、「リストはhashableでないから集合の要素になれない」と理解しておくのが無難です。ついでに、「リストはhashableでないから辞書のkeyになれない
」も覚えておいてください。

以下がややこしい説明です。
公式ドキュメントにははっきりと書かれていないのですが、pythonの言語設計にあたって辞書というものを実装するのは当然のことでした。python処理系に大きな影響を与えたSmalltalkで、辞書は処理系自体で必要であることが明らかになっていましたし、pythonでも属性の管理は原則として辞書で行われています。

辞書を実現するときに問題になるのはキーの問題です。変わらないものをキーにしたいのは当然です。推測ですが、キーに出来るものの候補としてimmutableという概念を入れてみたが、それではだめだったのでhashableを追加したのだと思います。

mutableはそのオブジェクトのクラス(type)によって決るものですが、hashableは(インスタンス)オブジェクトに対して決るものです。

具体的には以下のようになります。

python

1>>> a = (0, 1) 2>>> b = ([0], 1) 3>>> type(a) 4<class 'tuple'> 5>>> type(b) 6<class 'tuple'> 7>>> hash(a) 8-1950498447580522560 9>>> hash(b) 10Traceback (most recent call last): 11 File "<stdin>", line 1, in <module> 12TypeError: unhashable type: 'list'

これは気持ち悪いのですが、hashとはそういうものなのです。

hashがダークであるのは、mutableで、かつhashableなオブジェクトを作れてしまうことです。

投稿2021/01/16 10:52

編集2021/01/16 11:06
ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Python

1[d.get("lll") for d in bbb]

の部分をよーく考えてみましょう。get("lll") してくるっていうことはリストか None が入ってるんですよね?っていうことはリスト(と None)のリストが出来上がってしまっているのです。これを直すには色々ありますが素直に for 文で

Python

1result = [] 2for d in bbb: 3 xs = d,get('lll') 4 if not x is None: 5 result.extend(xs)

とするのがよいと思います。

投稿2021/01/16 09:34

A_kirisaki

総合スコア2853

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問