68

My question is very similar to this one, except I have a dictionary of lists and I'm interested in changing both the key value and all elements in every list form string to int.

So for instance I'd like the dictionary:

{ '1':['1', '2', '3', '4'] , '2':['1', '4'] , '3':['43','176'] }

to become:

{ 1:[1, 2, 3, 4] , 2:[1, 4] , 3:[43,176] }

Is this possible?

More in general since I created this dictionary from a JSON format file

{"0": ["1", "2", "3", "4"], "1": ["0", "2", "3", "4", "27", "94",
"95", "97", "128", "217", "218", "317"], "2": ["0", "1", "3", "4",
"94", "95"], "3": ["0", "1", "2", "4", "377"], "4": ["0", "1", "2",
"3", "27", "28"], "5": ["6", "7", "8"], "6": ["5", "7", "8"], "7":
["5", "6", "8", "14", "23", "40", "74", "75", "76", "362", "371",
"372"], "8": ["5", "6", "7", "66"], "9": ["10", "11", "12"], "10":
["9", "11", "12", "56", "130", "131"]}

with the following instructions:

json_data = open("coauthorshipGraph.txt")
coautorshipDictionary = json.load( json_data )
json_data.close()

is there a way to do it directly at loading time?

Bálint Sass
  • 310
  • 3
  • 11
Matteo
  • 7,924
  • 24
  • 84
  • 129
  • 1
    please note that `int(item)` raises an error if `item` cannot be converted to an int. It's important to wrap this with a `try .. except` block since you're reading from a file, which might have some unexpected values. – vikki Jan 17 '14 at 19:12
  • @vikki - thks for pointing out. Although I'm still a beginner and haven't got yet to the part of tutorial on exceptions I'll take note ;D – Matteo Jan 17 '14 at 19:15

4 Answers4

105
d = {'1':'145' , '2':'254' , '3':'43'}
d = {int(k):int(v) for k,v in d.items()}
>>> d
{1: 145, 2: 254, 3: 43}

for lists in values

>>> d = { '1':['1', '2', '3', '4'] , '2':['1', '4'] , '3':['43','176'] }
>>> d = {int(k):[int(i) for i in v] for k,v in d.items()}

in your case:

coautorshipDictionary = {int(k):int(v) for k,v in json.load(json_data)}

or

coautorshipDictionary = {
    int(k):[int(i) for i in v] for k,v in json.load(json_data)}
ndpu
  • 22,225
  • 6
  • 54
  • 69
  • Won't work for d = {'1' : ['2','3']} ... his values are lists. – Chris Arena Jan 17 '14 at 19:03
  • My example is not consistent with the `JSON` data I loaded though. In fact every element of the dictionary is a list and not a single int. Any changes I should do to your suggestion? – Matteo Jan 17 '14 at 19:04
  • For some reason `coautorshipDictionary = {int(k):int(v) for k,v in json.load(json_data)}` did not work for me. The JSON was loaded, but the values were not converted to INT. `d = {int(k):int(v) for k,v in d.items()}`, however, worked great, so I just loaded the JSON and then converted to INT in a second step. Odd. – Mark Cramer Sep 16 '17 at 17:11
7

Similar to Decency's answer, but taking advantage of the object_hook argument:

coautorshipDictionary = json.load(json_data, object_hook=lambda d: {int(k): [int(i) for i in v] if isinstance(v, list) else v for k, v in d.items()}) # iteritems() for Python 2

The main advantage of this method is that, if you ever end up with any nested dicts, the loader will handle each nested dict on its own as it loads the data without you having to write code to walk through your result dict. You could also add in checks for cases where values in lists are not numeric strings or the lists themselves contain dicts as well, if your JSON structure gets more complicated, and if your data will only have lists as the values for your top-level dict you can remove the if isinstance(v, list) else v part.

JAB
  • 20,783
  • 6
  • 71
  • 80
3

This solution will work for the case where you have an iterable as your value, as in the json you provided.

my_dict = {"0": ["1", "2", "3", "4"], "1": ["0", "2", "3", "4", "27", "94", "95", "97", "128", "217", "218", "317"], "2": ["0", "1", "3", "4", "94", "95"], "3": ["0", "1", "2", "4", "377"], "4": ["0", "1", "2", "3", "27", "28"], "5": ["6", "7", "8"], "6": ["5", "7", "8"], "7": ["5", "6", "8", "14", "23", "40", "74", "75", "76", "362", "371", "372"], "8": ["5", "6", "7", "66"], "9": ["10", "11", "12"], "10": ["9", "11", "12", "56", "130", "131"]}

output_dict = {}
for key, value in my_dict.iteritems():
    output_dict[int(key)] = [int(item) for item in value]

output_dict

Output:

{0: [1, 2, 3, 4],
 1: [0, 2, 3, 4, 27, 94, 95, 97, 128, 217, 218, 317],
 2: [0, 1, 3, 4, 94, 95],
 3: [0, 1, 2, 4, 377],
 4: [0, 1, 2, 3, 27, 28],
 5: [6, 7, 8],
 6: [5, 7, 8],
 7: [5, 6, 8, 14, 23, 40, 74, 75, 76, 362, 371, 372],
 8: [5, 6, 7, 66],
 9: [10, 11, 12],
 10: [9, 11, 12, 56, 130, 131]}

For the second part of the question, you can use a dict comprehension in line as you read the file. It's obfuscated as hell though.

with open('coauthorshipGraph.txt', 'r') as f:
    json_data = { int(key) : [int(item) for item in value] for key, value in json.load(f).iteritems()}

json_data

This yields the same output as above.

Chris Arena
  • 1,602
  • 15
  • 17
0
dict = { 'a':'100', 'b':'200', 'c':'300', 'd':'four_hundred', 'e':'500' }
dict_parse = {k: int(v) if v.isnumeric() else v for k, v in dict.items()}
>>> dict_parse
{ 'a': 100, 'b': 200, 'c': 300, 'd':'four_hundred', 'e':500}

When having a Python object (dict) that contains values with alphabetical strings and numerical strings, we can map and check against their type with string.isnumeric(), when dealing with float numbers amend the if statement to replace decimal point - you can apply same principal to negative numbers:

dict = { 'a':'10.0', 'b':'20.12', 'c':'300.3', 'd':'four_hundred', 'e':'500' }
dict_parse = {k: float(v) if v.replace(".", "").isnumeric() else v for k, v in dict.items()}

>>> dict_parse
{ 'a': 10.0, 'b': 20.12, 'c': 300.3, 'd':'four_hundred', 'e':500}
pasujemito
  • 312
  • 4
  • 16