다음과 같은 파일을 가져 오려고합니다.
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'
. 사전의 키가 목록이 될 수 없다는 것을 알고 있지만 내 값을 키가 아닌 목록으로 만들려고합니다. 어딘가에서 실수를했는지 궁금합니다.
답변
다른 답변에서 알 수 있듯이 오류는 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:
)을 사용하여 파일을 열 수도 있으며 제대로 작동합니다.
답변
참고 :
이 답변은 질문에 명시 적으로 답변하지 않습니다. 다른 답변은 그것을합니다. 질문은 시나리오 와 관련이 있고 발생한 예외는 general 이므로이 답변은 일반적인 경우를 가리 킵니다.
해시 값은 사전 조회 중에 사전 키를 빠르게 비교하는 데 사용되는 정수일뿐입니다.
내부적으로 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
이 오류를 방지하는 해결책은 목록 대신 중첩 된 튜플을 갖도록 목록을 재구성하는 것입니다.
답변
k
(목록)을 키로 사용하려고합니다 d
. 목록은 변경 가능하며 사전 키로 사용할 수 없습니다.
또한 다음 줄 때문에 사전에있는 목록을 초기화하지 않습니다.
if k not in d == False:
다음 중 하나 여야합니다.
if k not in d == True:
실제로는 다음과 같습니다.
if k not in d:
답변
당신이 얻고있는 이유 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']}
답변
이 TypeError
때문에 일어나고 k
이 광고와 다른리스트에서 슬라이스를 이용하여 생성되기 때문에, 목록이다 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
코드 의 논리를 대체합니다 .
답변
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)