这是《python 编程实践》这本书,第九章,最后一道题,14题。
稀疏向量(sparse vector)就是其元素几乎都为0的那种向量,比如[1,0,0,0,0,0,3,0,0,0] 如果将这些0 都保存到列表中实在是有些浪费存储内存。因此程序员常常会利用字典来保存其中的非零元素。比如说,刚才那个向量会写成{0:1, 6:3}, 这是因为, 该向量位置0处的值为1, 位置6 处的值为3.
a)编写一个叫sparse_add的函数,其参数为两个以字典为形式存储的稀疏向量,要求返回一个表示他们和的新字典。
b)编写一个名为sparse_dot的函数,其作用是计算两个稀疏向量的点积
c)你的上司要求你编写一个名为sparse_len的函数,其作用是返回一个稀疏向量的长度(就好像python中的len函数一样可以返回列表的长度那样。)纳闷,在编写该函数执勤,你还需要问他点什么呢?
好了,为了解决问题。
先上一部分铺垫内容:
字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据。python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的,且key必须是可哈希的。可哈希表示key必须是不可变类型,如:数字、字符串、只含不可变类型元素的元组(1,2,3,’abc’)、实现__hash__()方法的自定义对象(因为__hash__()须返回一个整数,否则会出现异常:TypeError: an integer is required)。可以用hash(obj)检测对象是否是可哈希的。
>>> class HashEnable(object):
... def __hash__(self):
... return 1
>>> he = HashEnable()
>>> hash(he)
1
>>> d = {he:1}
>>> d = {['1',2]:2}
Traceback (most recent call last):
File "", line 1, in
TypeError: unhashable type: 'list'
list 是 mutable的,可变的,所以不能有固定的hash值,所以unhashable , 出错。首先要将数组变成tuple元组就好多了。
为什么写关于tuple的东西呢,因为在很多增加set集合元素的时候,list列表里面的元素不能被append增加上,因为list是mutable可变的。由于tuple元组是immutable不可变的,所以,我们可以用tuple(一个list),来返回一个不可变的元组,这样就能增加大set中了。
关于这个上面的习题,这里第一题a)与b)几乎是一样的,只要
分两个过程
一个是叫
decode 解码: 将 输入的dict字典转换成添上相应位置0的完整list列表。
encode 编码:将 处理完成后的新的list列表转换呈新得dict字典。
于是我们可以这样做。
"""
A program to zip and unzip codes, to describe a list, which has many "0" elements, in a dict
"""
def sparse_add(dict1, dict2):
dict_new = {} # the dict_new derived from dict1, dict
list1 = [] # list1 for dict1
list2 = [] # list2 for dict2
summed = [] # summed for dict1 and dict2
temp1 = dict1.items() # a list from dict1
temp2 = dict2.items() # a list from dict2
"""
Decode section
"""
for i in range(10):
"""for dict1 to be appened into list1
"""
list1.append( dict1.get(i,0) )
list2.append( dict2.get(i,0) )
"""
这里是由于没有使用dict1.get(i,0)的形式的尝试,非常笨拙,效率很低,而且错误。得出的结论就是,多多使用意境写好的方法
"""
#if i < len(temp1):
#if temp1[i][0]: #if it exists, then it be appended to list1
#list1.append(temp1[i][1])
#else:
#list1.append(0) # if not exists, just append 0
#else:
#list1.append(0) # if not exists,
#"""for dict2 to be appened into list2
#"""
#if i < len(temp2):
#if temp2[i][0]:
#list2.append(temp2[i][1])
#else:
#list2.append(0)
#else:
#list2.append(0)
summed.append((list1[i] + list2[i]))
"""
Encode section
"""
for i in range(len(summed)):
if summed[i] != 0 : # if not 0, then be in dict_new
temp = {i:summed[i]}
dict_new.update(temp)
print dict_new
import sparse_add_out
dict1 = {0:3,5:2,6:10}
dict2 = {0:4,4:11,9:1}
sparse_add_out.sparse_add(dict1,dict2)
{0: 7, 9: 1, 4: 11, 5: 2, 6: 10}
后面的b)与c)就很简单了,简单的修改一下上面的代码就好了。 不超过20行就能完成。