-1

I'm working on a school assignment that asks me to:

1)Take my previously created dictionary and write it to a file as a string.

2)Then import that dictionary to python again and invert it

3)Write the inverted dictionary to a new file.

I asked a question about this program previously and got a great answer but I'm still having a rough time getting through an error. When I try running the program I get a Type error: unhashable type: 'list'. I am assuming it has to do with the invert function.

When I run that function in a separate script using the ChessPlayerProfile dictionary it seems to work fine. But when I try to use it in this script through the return dictionary from Read_Invert_Write function's output I get the error.

Any ideas what I am doing wrong? Any help would be appreciated. Here is the code and output:



    import os
    import json
    
    ChessPlayerProfile = {
        "Matt": [("Rating: ", 2200), ("FIDE ID: 0147632DF"), ("Member Status: ", True)],
        "Will": [("Rating: ", 2200), ("FIDE ID: 3650298MK"), ("Member Status: ", False)],
        "Jithu": [("Rating: ", 1900), ("FIDE ID: 5957200LH"), ("Member Status: ", True)],
        "Lisa": [("Rating: ", 2300), ("FIDE ID: 7719328CX"), ("Member Status: ", False)],
        "Nelson": [("Rating: ", 2500), ("FIDE ID: 6499012XX"), ("Member Status: ", True)],
        "Miles": [("Rating: ", 1600), ("FIDE ID: 4392251TJ"), ("Member Status: ", True)],
    }
    
    
    def write2file():
        with open("chessdict.txt", "w+") as f:
            json.dump(ChessPlayerProfile, f)
    
    
    
    def Read_Invert_Write():
        with open("chessdict.txt", "r") as f:
            Content = (json.load(f))
            Content = dict(Content)
            invert(Content)
            with open("newoutput.txt", "w+") as f:
                json.dump(Content, f)
    
    
    
    def invert(d):
        inverse = dict()
        for key in d:
            val = d[key]
            for item in val:
                if item not in inverse:
                    inverse[item] = [key]
                else:
                    inverse[item].append(key)
        print(inverse)
        return inverse
    
    
    def main():
        write2file()
        Read_Invert_Write()
    main()

Output:



    Traceback (most recent call last):
      File "/home/vigz/PycharmProjects/pythonProject/copytest2.py", line 46, in 
        main()
      File "/home/vigz/PycharmProjects/pythonProject/copytest2.py", line 45, in main
        Read_Invert_Write()
      File "/home/vigz/PycharmProjects/pythonProject/copytest2.py", line 24, in Read_Invert_Write
        invert(Content)
      File "/home/vigz/PycharmProjects/pythonProject/copytest2.py", line 35, in invert
        if item not in inverse:
    TypeError: unhashable type: 'list'

2 Answers2

0

JSON doesn't have separate list or tuple types. It was based on Javascript, not Python. JSON has a single sequence type, JSON arrays, and the Python json module serializes both lists and tuples as JSON arrays.

When you load the serialized JSON, JSON arrays get deserialized as Python lists. That means the values of your new dict are now lists of lists instead of lists of tuples. When you run your for item in val loop, item is a list instead of a tuple, and if item not in inverse is an attempt to perform a dict lookup with an unhashable key.

Unrelated, if you meant for ("FIDE ID: 0147632DF") to be a tuple, you need a trailing comma: ("FIDE ID: 0147632DF",). Alternatively, it would probably make more sense to use a 2-element tuple, following the format of the other tuples: ("FIDE ID: ", "0147632DF"). Or, instead of a list of 2-element tuples, a dict might be a more convenient data representation.

user2357112 supports Monica
  • 215,440
  • 22
  • 321
  • 400
  • Very true! I've switched up those FIDE ID's to be two strings in a tuple to match the rest of them. But from what I am understanding it seems no matter what I do I won't be able to invert that dictionary as long as I am using JSON to serialize the dictionary? – Vigz McHardthrust Mar 19 '21 at 06:15
  • @VigzMcHardthrust: You don't have to keep the data representation `json.loads` gives you. You can do stuff like convert lists into tuples if that's appropriate for your use case. – user2357112 supports Monica Mar 19 '21 at 06:23
  • You have been super helpful in getting me to understand this. I am grateful. – Vigz McHardthrust Mar 19 '21 at 06:27
0

Can you please add what is your expected output?

You are seeing the error because in a dict, the key has to be of hashable data type. lists are not hashable (abstractly speaking, immutable)

So to make your program run without errors. You can try this. But from the output, I don't think this is what you wanted your program to do

import os
import json
    
ChessPlayerProfile = {
    "Matt": [("Rating: ", 2200), ("FIDE ID: 0147632DF"), ("Member Status: ", True)],
    "Will": [("Rating: ", 2200), ("FIDE ID: 3650298MK"), ("Member Status: ", False)],
    "Jithu": [("Rating: ", 1900), ("FIDE ID: 5957200LH"), ("Member Status: ", True)],
    "Lisa": [("Rating: ", 2300), ("FIDE ID: 7719328CX"), ("Member Status: ", False)],
    "Nelson": [("Rating: ", 2500), ("FIDE ID: 6499012XX"), ("Member Status: ", True)],
    "Miles": [("Rating: ", 1600), ("FIDE ID: 4392251TJ"), ("Member Status: ", True)],
}
    
    
def write2file():
    with open("chessdict.txt", "w+") as f:
        json.dump(ChessPlayerProfile, f)



def Read_Invert_Write():
    with open("chessdict.txt", "r") as f:
        Content = (json.load(f))
        print(Content['Matt'])
        invert(Content)
        with open("newoutput.txt", "w+") as f:
            json.dump(Content, f)



def invert(d):
    inverse = dict()
    for key in d:
        val = d[key]
        for item in val:
            if tuple(item) not in inverse.keys():
                inverse[tuple(item)] = [key]
            else:
                inverse[tuple(item)].append(key)
    print(inverse)
    return inverse
    
    
def main():
    write2file()
    Read_Invert_Write()
main()

nodaj
  • 60
  • 5
  • Thanks for the response. What I am trying to get it to do to the dictionary is invert keys and values so the dictionary output in the new file looks like this: {('Rating: ', 2200): ['Matt', 'Will'], 'FIDE ID: 0147632DF': ['Matt'], ('Member Status: ', True): ['Matt', 'Jithu', 'Nelson'], 'FIDE ID: 3650298MK': ['Will'], ('Member Status: ', False): ['Will', 'Lisa'], ('Rating: ', 1900): ['Jithu'], 'FIDE ID: 5957200LH': ['Jithu'], ('Rating: ', 2300): ['Lisa'], 'FIDE ID: 7719328CX': ['Lisa'], ('Rating: ', 2500): ['Nelson'], 'FIDE ID: 6499012XX': ['Nelson']} – Vigz McHardthrust Mar 19 '21 at 06:12
  • Oooo! This works though! Im getting the correct output after your addition of inverse[tuple(item)] = [key] but without the invert(Content[Matt]) change. Awesome! Thank you. Now we are back in business. – Vigz McHardthrust Mar 19 '21 at 06:22