Related
Okay, so I am having this issue with JSON, keys, and strings. I'm using a JSON dump in python to save my game dictionaries and it does work. The issue is when I load the dictionaries the game I'm making uses int values as keys in the world directory but JSON stores keys as strings. Here's a random generation I did.
worldmap = {
'Regions': {
1: 'Zelbridge', 2: 'Forest Path', 3: 'Baronbell', 4: 'Old Path', 5: 'Cariva', 6: 'Prairie Path'},
'Zelbridge': {1: 'Field', 2: 'Prairie Path', 3: 'School', 4: 'Mountain Path', 5: 'Graveyard',
6: 'Old Path', 7: 'Blacksmith', 8: 'Forest Path', 9: 'Doctor', 0: 'Zelbridge'},
'Forest Path': {1: 'Trees', 2: 'Bushes', 3: 'Path', 4: 'Cariva', 5: 'Path',
6: 'Baronbell', 7: 'Path', 8: 'Zelbridge', 9: 'Path', 0: 'Forest Path'},
'Baronbell': {1: 'House', 2: 'Mountain Path', 3: 'Graveyard', 4: 'Old Path', 5: 'Field',
6: 'Forest Path', 7: 'Church', 8: 'Prairie Path', 9: 'Shop', 0: 'Baronbell'},
'Old Path': {1: 'Path', 2: 'Trees', 3: 'Bushes', 4: 'Cariva', 5: 'Path',
6: 'Zelbridge', 7: 'Trees', 8: 'Baronbell', 9: 'Trees', 0: 'Old Path'},
'Cariva': {1: 'Cellar', 2: 'Old Path', 3: 'Graveyard', 4: 'Mountain Path', 5: 'Town Hall',
6: 'Prairie Path', 7: 'School', 8: 'Forest Path', 9: 'Blacksmith', 0: 'Cariva'},
'Prairie Path': {1: 'Bushes', 2: 'Path', 3: 'Path', 4: 'Zelbridge', 5: 'Trees',
6: 'Cariva', 7: 'Trees', 8: 'Baronbell', 9: 'Path', 0: 'Prairie Path'}
}
So when I use the load function I get key errors due to the int's being converted to strings. I attempted a for loop to iterate over the keys and change them back but I get this error about the dictionary changing. Here's an example of me trying to load a different (and also random) world. Its set to print after each loop showing that it works
What was your hero's name? #Input hero name
Loading...
{'2': 'Prairie Path', '3': 'Cariva', '4': 'Old Path', '5': 'Baronbell', '6': 'Mountain Path', 1: 'Zelbridge'} #Region number 1 no longer string
{'3': 'Cariva', '4': 'Old Path', '5': 'Baronbell', '6': 'Mountain Path', 1: 'Zelbridge', 2: 'Prairie Path'} #Region numbers 1 and 2 no longer string
{'4': 'Old Path', '5': 'Baronbell', '6': 'Mountain Path', 1: 'Zelbridge', 2: 'Prairie Path', 3: 'Cariva'} #ect
{'5': 'Baronbell', '6': 'Mountain Path', 1: 'Zelbridge', 2: 'Prairie Path', 3: 'Cariva', 4: 'Old Path'} #ect
{'6': 'Mountain Path', 1: 'Zelbridge', 2: 'Prairie Path', 3: 'Cariva', 4: 'Old Path', 5: 'Baronbell'} # Region numbers 1, 2, 3, 4, and 5 no longer string
{'6': 'Mountain Path', 1: 'Zelbridge', 2: 'Prairie Path', 3: 'Cariva', 5: 'Baronbell'}
Traceback (most recent call last):
File "C:/Users/crazy/PycharmProjects/rpg/main.py", line 581, in load
for key in worldmap["Regions"]:
RuntimeError: dictionary changed size during iteration
Process finished with exit code 1
I'm not exactly sure what's wrong with it but sadly I'll also have to do this for each location within a region. Any and all help is appreciated, as I've looked all over SO and google but to no avail.
with open(world_file) as infile:
worldmap = json.load(infile)
copy = worldmap.copy()
regions = worldmap["Regions"]
locations = copy.pop("Regions")
for key in worldmap["Regions"]:
value = worldmap["Regions"][key]
new_key = int(key)
worldmap["Regions"].update({new_key: value})
worldmap ["Regions"].pop(key)
print(str(worldmap["Regions"]) + "\n")```
Use For loop this way and update the key in loop itself:
mydict = {1: 'a', 2: 'b'}
for index, (key, value) in enumerate(mydict.items()):
print("index: {}, key: {}, value: {}".format(index, key, value))
mydict[index] = mydict.pop(key)
Or use can use List to force a copy of the keys to be made:
mydict = {1: 'a', 2: 'b'}
for index, key in enumerate(list(mydict)):
mydict[index] = mydict.pop(key)
# which will give output like:
# ---------------------------
# {0: 'a', 1: 'b'}
I have this dictionary:
{
0: array([-0.16638531, -0.11749843]),
1: array([-0.2318372 , 0.00917023]),
2: array([-0.42934129, -0.0675385 ]),
3: array([-0.63377579, -0.02102854]),
4: array([-0.26648222, -0.42038916]),
5: array([-0.17250316, -0.73490218]),
6: array([-0.42774336, -0.61259704]),
7: array([-0.55420825, -0.77304496]),
8: array([0.13900166, 0.07800885]),
9: array([0.42223986, 0.16563338]),
10: array([ 0.39895669, -0.09198566]),
12: array([0.24324618, 0.44829616]),
11: array([ 0.55394714, -0.17960723]),
13: array([0.192127 , 0.5988793]),
14: array([0.39554203, 0.7186038 ]),
15: array([0.53721604, 1. ])
}
I want to convert those numpy.ndarray values to tuples, and have something like this:
{
0: (-0.16638531, -0.11749843),
1: (-0.2318372 , 0.00917023),
...
}
From this answer here it looks like for each value in the dictionary you can:
tuple(arr)
So for the whole dictionary you can probably do something like:
new_dict = {key: tuple(arr) for key, arr in old_dict.items()}
Or easier to understand:
new_dict = {}
for key, arr in old_dict.items():
new_dict.update({key: tuple(arr)})
You can use a dictionary comprehension.
Python dictionaries have an .items() method that return a tuple of (key, value) for each key-value pair.
The comprehension recreates a new mapping with the original key and the array cast as a tuple.
from numpy import array
data = {
0: array([-0.16638531, -0.11749843]),
1: array([-0.2318372 , 0.00917023]),
2: array([-0.42934129, -0.0675385 ]),
3: array([-0.63377579, -0.02102854]),
4: array([-0.26648222, -0.42038916]),
5: array([-0.17250316, -0.73490218]),
6: array([-0.42774336, -0.61259704]),
7: array([-0.55420825, -0.77304496]),
8: array([0.13900166, 0.07800885]),
9: array([0.42223986, 0.16563338]),
10: array([ 0.39895669, -0.09198566]),
12: array([0.24324618, 0.44829616]),
11: array([ 0.55394714, -0.17960723]),
13: array([0.192127 , 0.5988793]),
14: array([0.39554203, 0.7186038 ]),
15: array([0.53721604, 1. ])
}
print({key: tuple(value) for key, value in data.items()})
OUTPUT:
{0: (-0.16638531, -0.11749843), 1: (-0.2318372, 0.00917023), 2: (-0.42934129, -0.0675385), 3: (-0.63377579, -0.02102854), 4: (-0.26648222, -0.42038916), 5: (-0.17250316, -0.73490218), 6: (-0.42774336, -0.61259704), 7: (-0.55420825, -0.77304496), 8: (0.13900166, 0.07800885), 9: (0.42223986, 0.16563338), 10: (0.39895669, -0.09198566), 12: (0.24324618, 0.44829616), 11: (0.55394714, -0.17960723), 13: (0.192127, 0.5988793), 14: (0.39554203, 0.7186038), 15: (0.53721604, 1.0)}
mapping = { key: (item[0], item[1]) for key, item in your_dict.items() }
From dictionary :
{0: (u'Donald', u'PERSON'), 1: (u'John', u'PERSON'), 2: (u'Trump', u'PERSON'), 14: (u'Barack', u'PERSON'), 15: (u'Obama', u'PERSON'), 17: (u'Michelle', u'PERSON'), 18: (u'Obama', u'PERSON'), 30: (u'Donald', u'PERSON'), 31: (u'Jonh', u'PERSON'), 32: (u'Trump', u'PERSON')}
I'd like to create another dictionary as follows:
{u'Donald John Trump': 2, u'Barack Obama':1, u'Michele Obama':1}
Here 0,1,2 and 30,31,32 keys are increasing by 1 and occurred twice. And 14,15 17,18 occurred once each. Is there any way to create such dict?
I think the main problem you need to solve is to identify persons by grouping keys denoting an increasing int sequence, as you described it.
Fortunately, Python has a recipe for this.
from itertools import groupby
from operator import itemgetter
from collections import defaultdict
dct = {
0: ('Donald', 'PERSON'),
1: ('John', 'PERSON'),
2: ('Trump', 'PERSON'),
14: ('Barack', 'PERSON'),
15: ('Obama', 'PERSON'),
17: ('Michelle', 'PERSON'),
18: ('Obama', 'PERSON'),
30: ('Donald', 'PERSON'),
31: ('John', 'PERSON'),
32: ('Trump', 'PERSON')
}
persons = defaultdict(int) # Used for conveniance
keys = sorted(dct.keys()) # So groupby() can recognize sequences
for k, g in groupby(enumerate(keys), lambda d: d[0] - d[1]):
ids = map(itemgetter(1), g) # [0, 1, 2], [14, 15], etc.
person = ' '.join(dct[i][0] for i in ids) # "Donald John Trump", "Barack Obama", etc
persons[person] += 1
print(persons)
# defaultdict(<class 'int'>,
# {'Barack Obama': 1,
# 'Donald John Trump': 2,
# 'Michelle Obama': 1})
def add_name(d, consecutive_keys, result):
result_key = ' '.join(d[k][0] for k in consecutive_keys)
if result_key in result:
result[result_key] += 1
else:
result[result_key] = 1
d = {0: (u'Donald', u'PERSON'), 1: (u'John', u'PERSON'), 2: (u'Trump', u'PERSON'),
14: (u'Barack', u'PERSON'), 15: (u'Obama', u'PERSON'),
17: (u'Michelle', u'PERSON'), 18: (u'Obama', u'PERSON'),
30: (u'Donald', u'PERSON'), 31: (u'John', u'PERSON'), 32: (u'Trump', u'PERSON')}
sorted_keys = sorted(d.keys())
last_key = sorted_keys[0]
consecutive_keys = [last_key]
result = {}
for i in sorted_keys[1:]:
if i == last_key + 1:
consecutive_keys.append(i)
else:
add_name(d, consecutive_keys, result)
consecutive_keys = [i]
last_key = i
add_name(d, consecutive_keys, result)
print(result)
Output
{'Donald John Trump': 2, 'Barack Obama': 1, 'Michelle Obama': 1}
i have this dict:
dict_meses = {1: 'Enero', 2: 'Febrero', 3: 'Marzo', 4: 'Abril', 5: 'Mayo', 6: 'Junio', 7: 'Julio', 8: 'Agosto',
9: 'Setiembre', 10: 'Octubre', 11: 'Noviembre', 12: 'Diciembre'}
I need to change the month on a string like this '14/1/2015' for the month that corresponds in the dict. For example if a have '14/1/2015' i need to change it to '1/Enero/2015'
I am trying to do something like this:
def xxx(days): -----> days is a list of tuples like this [('14/1/2015', 500), ...]
dict_months = {1: 'Enero', 2: 'Febrero', 3: 'Marzo', 4: 'Abril', 5: 'Mayo', 6: 'Junio', 7: 'Julio', 8: 'Agosto',
9: 'Setiembre', 10: 'Octubre', 11: 'Noviembre', 12: 'Diciembre'}
days_list = []
for i in days:
lista = list(i)
fecha_entera = lista[0].split('/') ---> ['14','1','2015']
dia = fecha_entera[1] ----------------> '1'
if int(dia) in dict_meses.keys():
fecha_entera[1] = ????------------> want to change '1' to 'Enero'
dias_lista.append(fecha_entera)
return dias_lista
Question: How can i take the value that corresponds to the key that the day represents?
If i am not explaining this to clear just let me know and i will try harder.
Thanks in advance for the help provided
For a string solution, use the string "replace" function on "/1/".
lista.replace("/" + dia + "/", "/" + dict_months[int(dia)] + "/")
You can use datetime to parse your dates using %B with srftime to get the output you want:
from datetime import datetime
dte = '14/1/2015'
print(datetime.strptime(dte,"%d/%m/%Y").strftime("%d/%B/%Y"))
%B will give you the locale’s full month name.
In [1]: from datetime import datetime
In [2]: dte = '14/1/2015'
In [3]: import locale
In [4]: locale.setlocale(locale.LC_ALL,"es_SV.utf_8")
Out[4]: 'es_SV.utf_8'
In [5]: print(datetime.strptime(dte,"%d/%m/%Y").strftime("%d/%B/%Y"))
14/enero/2015
If every first element is a date string:
def xxx(days):
return [datetime.strptime(dte, "%d/%m/%Y").strftime("%d/%B/%Y")
for dte, _ in days]
If you want to use your dict:
def xxx(days):
dict_months = {"1": 'Enero', "2": 'Febrero', "3": 'Marzo', "4": 'Abril', "5": 'Mayo', "6": 'Junio', "7": 'Julio',
"8": 'Agosto',
"9": 'Setiembre', "10": 'Octubre', "11": 'Noviembre', "12": 'Diciembre'}
days_list = []
for sub in map(list, days):
dy, mn, year = sub[0].split()
days_list.append("{}/{}/{}".format(dy, dict_months[mn], year))
return days_list
You should use the keys as strings, it is pointless having to cast to int to compare.
I am reading excel file and creating dictionary using following code in file a.py.
productNo = int(worksheet.cell_value(curr_row, 1))
print "Product No :" + str(productNo)
products[productNo] = {}
while curr_cell < num_cells:
curr_cell += 1
header = str(worksheet.cell_value(0, curr_cell))
# Cell Types: 0=Empty, 1=Text, 2=Number, 3=Date, 4=Boolean, 5=Error, 6=Blank
cell_type = worksheet.cell_type(curr_row, curr_cell)
#print ' ',curr_cell,' <-> ', cell_type
cell_value = worksheet.cell_value(curr_row, curr_cell)
if cell_type == 0 or cell_type == 6:
products[productNo][header] = ""
if cell_type == 1:
#products[productNo] = {header :cell_value}
products[productNo][header] = cell_value
elif cell_type == 2:
cell_value = int(cell_value)
print "Header " + header
products[productNo][header] = cell_value
elif cell_type == 3:
products[productNo] = {header :cell_value}
elif cell_type == 4:
products[productNo] = {header :cell_value}
In file main.py I am calling above written code (in function) and catalouge.readExcel('D:/Personal/CatalogNo_1134.xls', products) by passing variable products as dictionary.
When dump it I am getting all keys and values.
print "Dump " + str(products)
print products.keys()
print products['28852']['ProductNo']
print products['28852']['Style']
Dump {28852: {'Category': u'Party Wear', 'Style': u'Designer', 'ProductNo': 28852, 'ProductGroup': u'Salwar Kameez', 'CatalogNo': 1134, 'ProductType': u'Salwar Kameez', 'SubCategoryDefinition': '', 'Fabric': u'Faux Georgette', 'MinWebPrice': 3395, 'Description': u'Capture The Exuberance Of Womanhood In Its Full Glory That Will Bring Out Your Fragility And Femininity. Genuine Magnificence Will Come Out Through The Dressing Style With This Off White Faux Georgette Salwar Kameez. The Appealing Lace|Resham Work Through The Attire Is Awe-Inspiring.', 'OptionOfSleeves': '', 'Rate/FreeSize': 2095, 'XLRate': 0, 'GenericName': u'Dress Material', 'SizeAvailable': u'Not Applicable', 'MaxLengthCholi': '', 'ItemTag': u'Enigmatic Off White Salwar Kameez', 'SubCategory': u'Other - Party Wear', 'Description of Blouse/Choli/Bottom': u'Paired With A Matching Bottom', 'Colour': u' Off White', 'Work': u'Lace|Resham', 'ExpressQty': 0, 'Occasion': u'Christmas,Diwali,Eid,Festival,Kitty Party,Mehendi,Navratri,Party Wear,Sangeet,Wedding', 'Weight': 1, 'Description of Dupatta': u'Comes With A Matching Dupatta', 'DeliveryDays': 8}, 28853: {...}}
keys are
[28852, 28853, 28854, 28855, 28856, 28857, 28858, 28859, 28860, 28861, 28862, 28863]
When I access it using products['28852']
Traceback (most recent call last):
print products['28852']['ProductNo']
KeyError: '28852'
You are accessing str 28852 while the key is integer. Please access with 28852.