Python: TypeError: unhashable type: 'list'
Я пытаюсь взять файл, который выглядит так
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'
. Я знаю, что ключи в словаре не могут быть списками, но я пытаюсь превратить свое значение в список, а не в ключ. Мне интересно, если я где-то допустил ошибку.
Ответы
Ответ 1
Как указано в других ответах, ошибка связана с 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:
), и он должен работать нормально.
Ответ 2
Вы пытаетесь использовать k
(который является списком) в качестве ключа для d
. Списки являются изменяемыми и не могут использоваться в качестве ключей dict.
Кроме того, вы никогда не инициализируете списки в словаре, из-за этой строки:
if k not in d == False:
Что должно быть:
if k not in d == True:
На самом деле это должно быть:
if k not in d:
Ответ 3
Примечание. Этот ответ не дает четкого ответа на заданный вопрос. другие ответы делают это. Поскольку вопрос относится к конкретному сценарию, а возникшее исключение является общим, этот ответ указывает на общий случай.
Хэш-значения - это просто целые числа, которые используются для быстрого сравнения ключей словаря во время поиска в словаре.
Внутренне метод 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
Решение этой ошибки состоит в том, чтобы реструктурировать список так, чтобы вместо списков были вложенные кортежи.
Ответ 4
Причина, по которой вы получаете 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']}
Ответ 5
TypeError
происходит, потому что k
- это список, так как он создается с использованием фрагмента из другого списка с линией k = list[0:j]
. Вероятно, это должно быть что-то вроде k = ' '.join(list[0:j])
, поэтому у вас есть строка.
В дополнение к этому ваш оператор if
неверен, как указано в ответе Джесси, который должен читать 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
на ваш код.
Ответ 6
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)