问题:Python:TypeError:无法散列的类型:“列表”
我正在尝试拍摄一个看起来像这样的文件
AAA x 111
AAB x 111
AAA x 112
AAC x 123
...
并使用字典使输出看起来像这样
{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...}
这就是我尝试过的
file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline!= "":
list = []
list = readline.split(" ")
j = list.index("x")
k = list[0:j]
v = list[j + 1:]
d = {}
if k not in d == False:
d[k] = []
d[k].append(v)
readline = file.readline().rstrip()
我不断收到TypeError: unhashable type: 'list'
。我知道字典中的键不能是列表,但是我试图将我的值变成列表而不是键。我想知道我是否在某个地方犯了一个错误。
回答 0
如其他答案所示,错误是由于造成的k = list[0:j]
,您的密钥被转换为列表。您可以尝试做的一件事是重新编写代码以利用该split
功能:
# Using with ensures that the file is properly closed when you're done
with open('filename.txt', 'rb') as f:
d = {}
# Here we use readlines() to split the file into a list where each element is a line
for line in f.readlines():
# Now we split the file on `x`, since the part before the x will be
# the key and the part after the value
line = line.split('x')
# Take the line parts and strip out the spaces, assigning them to the variables
# Once you get a bit more comfortable, this works as well:
# key, value = [x.strip() for x in line]
key = line[0].strip()
value = line[1].strip()
# Now we check if the dictionary contains the key; if so, append the new value,
# and if not, make a new list that contains the current value
# (For future reference, this is a great place for a defaultdict :)
if key in d:
d[key].append(value)
else:
d[key] = [value]
print d
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
请注意,如果您使用的是Python 3.x,则必须稍作调整才能使其正常运行。如果您使用打开文件rb
,则需要使用line = line.split(b'x')
(确保使用正确的字符串类型分割字节)。您也可以使用with open('filename.txt', 'rU') as f:
(甚至with open('filename.txt', 'r') as f:
)打开文件,它应该可以正常工作。
回答 1
注意: 此答案未明确回答所提问题。其他答案可以做到。由于问题是特定于场景的,提出的异常是一般的,因此此答案指向一般情况。
哈希值只是整数,用于在字典查找期间快速比较字典关键字。
在内部,hash()
方法调用__hash__()
对象的方法,该方法默认为任何对象设置。
将嵌套列表转换为集合
>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
发生这种情况是因为列表内的列表是不能散列的列表。可以通过将内部嵌套列表转换为元组来解决,
>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])
显式哈希嵌套列表
>>> hash([1, 2, 3, [4, 5,], 6, 7])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(tuple([1, 2, 3, [4, 5,], 6, 7]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash(tuple([1, 2, 3, tuple([4, 5,]), 6, 7]))
-7943504827826258506
避免此错误的解决方案是将列表重组为具有嵌套元组而不是列表。
回答 2
您正在尝试使用k
(这是一个列表)作为的键d
。列表是可变的,不能用作字典键。
另外,由于这一行,您永远不会初始化字典中的列表:
if k not in d == False:
应该是:
if k not in d == True:
实际上应该是:
if k not in d:
回答 3
之所以会出现unhashable type: 'list'
异常,是因为k = list[0:j]
将其设置k
为列表的“切片”,从逻辑上讲,它是另一个(通常较短的)列表。您需要的只是获得列表中的第一项,这样写k = list[0]
。对于的调用返回的列表的第三个元素v = list[j + 1:]
应该是相同的。v = list[2]
readline.split(" ")
我注意到了代码的其他一些可能的问题,我将提及其中的一些问题。一个大的一个是你不希望(重新)初始化d
与d = {}
每一行的循环中读取。另一个是,将变量命名为任何内置类型通常不是一个好主意,因为它会阻止您在需要时访问其中一个变量,并且会使习惯于该变量的其他人感到困惑。指定这些标准项目之一的名称。因此,您应该将变量list
变量重命名为其他名称,以避免类似的问题。
这是您的工作版本,其中进行了这些更改,我还简化了if
您拥有的语句表达式,该语句表达式可检查键是否已在字典中-甚至有更短的隐式方法来执行此类操作,但使用条件语句声明目前还不错。
d = {}
file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline:
lst = readline.split(" ") # Split into sequence like ['AAA', 'x', '111'].
k = lst[0] # First item.
v = lst[2] # Third item.
if k not in d: # New key?
d[k] = [] # Initialize its associated value to an empty list.
d[k].append(v)
readline = file.readline().rstrip()
file.close() # Done reading file.
print('d: {}'.format(d))
输出:
d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
回答 4
之所以TypeError
会发生,k
是因为是一个列表,因为它是使用另一个带有line的列表中的一个切片创建的k = list[0:j]
。这可能类似于k = ' '.join(list[0:j])
,因此您需要一个字符串。
除此之外,if
正如Jesse的回答所指出的那样,您的陈述不正确,应该读为if k not in d
或if not k in d
(我更喜欢后者)。
您还需要d = {}
在for
循环中清除字典,因为每次迭代都在其中。
请注意,您也不应使用list
或file
作为变量名,因为您将掩盖内建函数。
这是我重写代码的方法:
d = {}
with open("filename.txt", "r") as input_file:
for line in input_file:
fields = line.split()
j = fields.index("x")
k = " ".join(fields[:j])
d.setdefault(k, []).append(" ".join(fields[j+1:]))
dict.setdefault()
上面的方法替换了if k not in d
代码中的逻辑。
回答 5
python 3.2
with open("d://test.txt") as f:
k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines())
d={}
for i,_,v in k:
d.setdefault(i,[]).append(v)