据我所知,由于像列表这样的不可用类型是变异的,因此不能将它们用作散列的密钥。但是,我不明白为什么他们的记忆地址(我不相信变化)可以使用?
例如:
my_list = [1,2,3]
my_dict = {my_list: 1} #error
my_dict = {id(my_list): 1} # no error
答案 0 :(得分:1)
如果你扩展list
,set
等,你实际上可以使用对象的内存地址作为哈希函数。
使用哈希的内存地址的主要原因是错误的是因为如果两个对象相等(a == b
求值为True
),我们也希望它们的哈希值相等(hash(a) == hash(b)
是True
)。否则,我们可能会出现意想不到的行为。
要查看此示例,请创建我们自己的扩展list
的类,并使用该对象的内存地址作为哈希函数。
>>> class HashableList(list):
def __hash__(self):
return id(self) # Returns the memory address of the object
现在我们可以创建两个可清除的列表!我们的HashableList
使用与python的内置列表相同的构造函数。
>>> a = HashableList((1, 2, 3))
>>> b = HashableList((1, 2, 3))
果然,正如我们所料,我们得到了
>>> a == b
True
我们可以列出我们的列表!
>>> hash(a)
1728723187976
>>> hash(b)
1728723187816
>>> hash(a) == hash(b)
False
如果查看最后3位数字,您会看到a
和b
在内存中相互靠近,但不在同一位置。由于我们使用内存地址作为哈希值,这也意味着它们的哈希值不相等。
如果比较两个相等元组(或任何其他可哈希对象)的内置哈希值会发生什么?
>>> y = ('foo', 'bar')
>>> z = ('foo', 'bar')
>>> y == z
True
>>> hash(y)
-1256824942587948134
>>> hash(z)
-1256824942587948134
>>> hash(y) == hash(z)
True
如果您自己尝试此操作,则('foo', 'bar')
的哈希值与我的匹配不匹配,因为每次新的python会话开始时字符串的哈希值都会更改。重要的是,在同一会话中,hash(y)
将始终等于hash(z)
。
让我们看看如果我们制作一个集合会发生什么,并使用HashableList
个对象和我们制作的元组。
>>> s = set()
>>> s.add(a)
>>> s.add(y)
>>> s
{[1, 2, 3], ('foo', 'bar')}
>>> a in s # Since hash(a) == hash(a), we can find a in our set
True
>>> y in s # Since hash(y) == hash(y), we can find y in our set
True
>>> b in s
False
>>> z in s
True
即使a == b
,我们也无法在集合中找到a
因为hash(b)
不等于hash(a)
,所以我们无法在 List<Product> prodata = new List<Product>();
RootObject _rootObject = new RootObject();
var list = db.productGetData().ToList();
foreach (var listdata in list)
{
var _listOfProperties = new List<Property>();
//if product list contains data of properties
foreach(var _prop in listdata.Properies)
{
var property = new Property();
property.PropertyKey = _prop.PropertyKey;
property.PropertyValue = _prop.PropertyValue;
_listOfProperties.Add(property);
}
Product pdata = new Product();
pdata.Properties = _listOfProperties;
prodata.Add(pdata);
}
_rootObject.Products = prodata;
and now serialize it
string stringData = JsonConvert.SerializeObject(_rootObject);
找到{{1}}。在集合中找到我们的等效列表!