web-dev-qa-db-ja.com

リストはハッシュ不可ですが、タプルはハッシュ可能ですか?

リストをハッシュするには? 最初にタプルに変換する必要があると言われました。 [1,2,3,4,5]から(1,2,3,4,5)

したがって、最初のものはハッシュできませんが、2番目のものはハッシュできます。なぜ*


*私は詳細な技術的説明を本当に探しているのではなく、直観を探しています

28
gsamaras

主に、タプルは不変だからです。次の作品を想定しています:

_>>> l = [1, 2, 3]
>>> t = (1, 2, 3)
>>> x = {l: 'a list', t: 'a Tuple'}
_

さて、l.append(4)を実行するとどうなりますか?辞書のキーを変更しました!遠くから!ハッシュアルゴリズムがどのように機能するかを熟知している場合、これは恐ろしいはずです。一方、タプルは絶対に不変です。 t += (1,)はタプルを変更しているように見えるかもしれませんが、実際にはそうではありません。単にnewタプルを作成し、辞書キーを変更しないままにします。

45
val

あなたは完全にその作品を作ることができますが、私はあなたが効果を好きではないに違いない。

_from functools import reduce
from operator import xor

class List(list):
    def __hash__(self):
        return reduce(xor, self)
_

次に、何が起こるか見てみましょう。

_>>> l = List([23,42,99])
>>> hash(l)
94
>>> d = {l: "Hello"}
>>> d[l]
'Hello'
>>> l.append(7)
>>> d
{[23, 42, 99, 7]: 'Hello'}
>>> l
[23, 42, 99, 7]
>>> d[l]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: [23, 42, 99, 7]
_

編集:それで、私はこれについてもう少し考えました。リストのidをハッシュ値として返す場合、上記の例を機能させることができます。

_class List(list):
    def __hash__(self):
        return id(self)
_

その場合、_d[l]_は_'Hello'_を提供しますが、_d[[23,42,99,7]]_もd[List([23,42,99,7])]も(新しい_[Ll]ist_を作成しているため)は提供しません。

7
L3viathan

リストは変更可能であるため、リストを変更すると、ハッシュも変更されます。これにより、ハッシュ(セットキーやdictキーなど)を持つポイントが失われます。

4
polku

リストは変更可能であり、タプルは変更できないためです。

4
Daniel Roseman

答えは良いです。その理由は、可変性です。 dict内のリストをキーとして使用できる場合; (または任意の可変オブジェクト)その後、そのキーを(偶然または故意に)変更することでキーを変更できます。これにより、ディクショナリ内のキーのハッシュ値に変更が発生します。そのため、そのキーによってそのデータ構造から値を追跡することはできません。ハッシュ値とハッシュテーブルは、実際の値エントリを保存するインデックスにマッピングすることにより、大きなデータを簡単にマッピングするために使用されます。

それらについての詳細はこちら:-

ハッシュテーブルハッシュ関数連想配列

1
Vicrobot

すべてのタプルがハッシュ可能というわけではありません。たとえば、タプルには要素としてリストが含まれます。

x = (1,[2,3])
print(type(x))
print(hash(x))
0
user1436465