Подтвердить что ты не робот

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'. Я знаю, что ключи в словаре не могут быть списками, но я пытаюсь превратить свое значение в список, а не в ключ. Мне интересно, если я где-то допустил ошибку.

4b9b3361

Ответ 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)