I have a json file like:
{
"parentNode": {
"id": "root",
"mbs": [
16995.9859862176,
-6029.919928079834,
-4.6344976928710935,
4674.872691701428
]
},
"children": [
{
"id": "00t2",
"mbs": [
16561.761031809023,
-5189.992543469676,
5,
221.7414398051216
]
},
{
"id": "01t2",
"mbs": [
16851.244334748077,
-5189.992543469676,
5,
221.7414398051216
]
}
]
}
Now I want to change the mbs value but to take a log before for roll back.
so my code is like:
if jsondict['parentNode']:
mbsx=jsondict['parentNode']['mbs'][0]
mbsy=jsondict['parentNode']['mbs'][1]
nodeid=jsondict['parentNode']['id'] #log the node id and mbs value
jsondict['mymbs_parent']=[nodeid,mbsx,mbsy] #write em down
jsondict['parentNode']['mbs'][0]=mbsx+xoffset #then change the value
jsondict['parentNode']['mbs'][1]=mbsy+yoffset
That works fine for parent node,
but there maybe many children nodes, so for the children part, the code is like this:
if jsondict['children']:
count=len(jsondict['children'])
for i in range(count):
mbsx=jsondict['children'][i]['mbs'][0]
mbsy=jsondict['children'][i]['mbs'][1]
nodeid=jsondict['children'][i]['id']
jsondict['mymbs_children'][i]=(nodeid,mbsx,mbsy)
jsondict['children'][i]['mbs'][0]=mbsx+xoffset
jsondict['children'][i]['mbs'][1]=mbsy+yoffset
then I get list assignment index out of range error.
I guess there isn't mymbs_children in the json file yet so there isn't jsondict['mymbs_children'][i]
I haven't found out how to do it, any ideas?
I don't love your approach, but for simplicity I can answer the question you have asked. To fix the error you are getting, add
jsondict['mymbs_children'] = []
as the first line in the block after
if jsondict['children']:
This will create the list which you are then trying to write to.
Then you need to use .append() to add the items to the list:
jsondict['mymbs_children'].append((nodeid,mbsx,mbsy))
instead of
jsondict['mymbs_children'][i]=(nodeid,mbsx,mbsy)
you can put an if condition surrounding the for loop to check:
...
if count > 0:
for i in range(count):
...
for python 3.8 onwards, you can use walrus operator as well to cut down the number of lines of code: (for more info)
...
if (count := len(jsondict['children'])) > 0:
for i in range(count):
...
another way which I prefer is to not use range:
...
for child in jsondict['children']:
child['mbs'][blah]...
...
this will avoid the issue of out of range index, and you might not even need to use the count variable
# Key "mymbs_children" is not present in the dictionary yet,
# so you'll need to declare it first and initialise to an empty list.
jsondict['mymbs_children'] = []
if jsondict['children']:
count=len(jsondict['children'])
for i in range(count):
mbsx=jsondict['children'][i]['mbs'][0]
mbsy=jsondict['children'][i]['mbs'][1]
nodeid=jsondict['children'][i]['id']
# Use append to add the tuple to this list
jsondict['mymbs_children'].append((nodeid,mbsx,mbsy));
Related
I want to create a dictionary with Key value pairs which are filled via an for Loop
The dictionary I want to achive
[
{
"timestamp": 123123123,
"image": "image/test1.png"
},
{
"timestamp": 0384030434,
"image": "image/test2.png"
}
]
My code does not work and I´m new to the datatypes of python.
images_dict = []
for i in images:
time = Image.open(i)._getexif()[36867]
images_dict = {"timestamp": time, "image": i}
What am I missing?
First, you seem to be confusing the definition of a list and a dictionary in python. Dictionaries use curly brackets {} and lists use regular brackets []. So in your first example, you are describing a list with a single element, which is a dictionary.
As for your code example, you are creating an empty list, and then iterating over images which I assume is a list of images, and then redefining the variable images_dict to be a dictionary with two key: value pairs for every iteration.
It seems like what you want is this:
images_dict = []
for image in images:
time = Image.open(1)._getexif()[36867]
images_dict.append({'timestamp': time, 'image': image})
The answer from Tom McLean worked for me, I´m a little bit confused with the dataypes of python
images_dict.append({"timestamp": time, "image": i})
I have a JSON file that looks like this:
{
"returnCode": 200,
"message": "OK",
“people”: [
{
“details: {
"first": “joe”,
“last”: doe,
“id”: 1234567,
},
“otheDetails”: {
“employeeNum”: “0000111222”,
“res”: “USA”,
“address”: “123 main street”,
},
“moreDetails”: {
“family”: “yes”,
“siblings”: “no”,
“home”: “USA”,
},
},
{
“details: {
"first": “jane”,
“last”: doe,
“id”: 987654321,
},
“otheDetails”: {
“employeeNum”: “222333444”,
“res”: “UK”,
“address”: “321 nottingham dr”,
},
“moreDetails”: {
“family”: “yes”,
“siblings”: “yes”,
“home”: “UK,
},
}
This shows two entries, but really there are hundreds or more. I do not know the number of entries at the time the code is run.
My goal is to iterate through each entry and get the 'id' under "details". I load the JSON into a python dict named 'data' and am able to get the first 'id' by:
data['people'][0]['details']['id']
I can then get the second 'id' by incrementing the '0' to '1'. I know I can set i = 0 and then increment i, but since I do not know the number of entries, this does not work. Is there a better way?
Less pythonic then a list comprehension, but a simple for loop will work here.
You can first calculate the number of people in the people list and then loop over the list, pulling out each id at each iteration:
id_list = []
for i in range(len(data['people'])):
id_list.append(data['people'][i]['details']['id'])
You can use dict.get method in a list comprehension to avoid getting a KeyError on id. This way, you can fill dictionaries without ids with None:
ids = [dct['details'].get('id') for dct in data['people']]
If you still get KeyError, then that probably means some dcts in data['people'] don't have details key. In that case, it might be better to wrap this exercise in try/except. You may also want to identify which dcts don't have details key, which can be gathered using error_dct list (which you can uncomment out from below).
ids = []
#error_dct = []
for dct in data['people']:
try:
ids.append(dct['details']['id'])
except KeyError:
ids.append(None)
#error_dct.append(dct)
Output:
1234567
987654321
I'm trying to create a dictionary from 3 lists and I'm having trouble with the values being overwritten.
My lists look like this:
hosts = ["Host1", "Host2" ...]
uptime = ["50", "60" ...]
downtime = ["50", "40" ...]
I need a dictionary that looks like this:
{"availability": [{"Host": "Host1", "Uptime": "50", "Downtime": "50"}, {"Host": "Host2", "Uptime": "60", "Downtime": "40"}]}
Here's my code:
availability_json = {"availability": {}}
for x in range(len(hosts)):
availability_json["availability"]["Host"] = hosts[x]
availability_json["availability"]["Uptime"] = uptime[x]
availability_json["availability"]["Downtime"] = downtime[x]
When I run it only the final list is included. I've also tried with dict comprehension with the same issue.
What you want is:
availability_json = {
"availability": [
{"Host": host, "Uptime": up, "Downtime": down}
for host, up, down in zip(hosts, uptime, downtime)
]
}
Your mistake is that you want to collect multiple instances of "availability", but you created a data structure that can hold only one of them.
You need a list. You even acknowledged this yourself,
I need a dictionary that looks like this:
{"availability": [{...}, {...}]}
where [ ... ] is the list. But in your code, you didn't create a list.
The adjustments you need to make in your code are:
initialize a dictionary containing a list, instead of a dictionary containing a dictionary
in every iteration of the loop, create a new "availability" dictionary (instead of reusing the same one each time), and append it to the list
availability_json = {"availability": []} # 1.
for x in range(len(hosts)):
a = {} # 2.
a["Host"] = hosts[x]
a["Uptime"] = uptime[x]
a["Downtime"] = downtime[x]
availability_json["availability"].append(a)
Of course, Python allows you to write the same more succinctly, as shown in orlp's answer.
I am trying to loop through a JSON file to get specific values, however, when doing so the loop is printing three times. I only want the value to print once and have tried breaking the loop but it still has not worked.
Python Code:
with open(filename) as json_filez:
dataz = json.load(json_filez)
for i in dataz:
for i in dataz['killRelated']:
print(i["SteamID"])
break
and a snippet of my json file is
{
"killRelated": [
{
"SteamID": "76561198283763531",
"kill": "15,302",
"shotacc": "16.1%"
}
],
"metaData": [
{
"test": "lol"
}
],
"miscData": [
{
"damageGiven": "2,262,638",
"gamePlayed": "1,292",
"moneyEarned": "50,787,000",
"score": "31,122",
"timePlayed": "22d 11h 56m"
}
]
}
and this is my output:
76561198283763531
76561198283763531
76561198283763531
Expected output:
76561198283763531
The return from json.load is a dictionary, and you are only interested in one entry in that, keyed by 'killRelated'. Now the "values" against each dictionary entry are lists, so that is what you need to be iterating though. And each element of such a list is a dictionary that you can again access via a key.
So your code could be:
with open(filename) as json_filez:
dataz = json.load(json_filez)
for kr in dataz['killRelated']: # iterate through the list under the top-level keyword
print (kr["SteamID"])
Now in your sample data, there's only one entry in the dataz['killRelated'] list, so you'll only get that one printed. But in general, you should expect multiple entries - and cater for the possibility of none. You can handle that by try/except of by checking key existence; here's the latter:
with open(filename) as json_filez:
dataz = json.load(json_filez)
if 'killRelated' in dataz: # check for the top keyword
for kr in dataz['killRelated']: # iterate through the list under this keyword
if 'steamID' in kr: # check for the next level keyword
print (kr["SteamID"]) # report it
You were getting three output lines because your outer loop iterated across all keyword entries in dataz (although without examining them), and then each time within that also iterated across the dataz['killRelated'] list. Your addition of break only stopped that inner loop, which for the particular data you had was redundant anyway because it was only going to print one entry.
Your code is correct. You should check your json file or you can share your full JSON text. That would be a problem. I run you code with json snippet you provided and it works as expected.
import json
with open("test.json") as json_filez:
dataz = json.load(json_filez)
for i in dataz:
for i in dataz['killRelated']:
print(i["SteamID"])
and the result as blow:
76561198283763531
First, here is a sample JSON feed that I want to read in Python 2.7 with either simplejson or the built in JSON decoder. I am loading the .json file in Python and then searching for a key like "Apple" or "Orange" and when that key is found, I want to bring in the information for it like the types and quantities.
Right now there is only 3 items, but I want to be able to search one that may have up to 1000 items. Here is the code:
{
"fruits": [
{
"Apple": [
{
"type": "Gala",
"quant": 5
},
{
"type": "Honeycrisp",
"quant": 10
},
{
"type": "Red Delicious",
"quant": 4
}
]
},
{
"Banana": [
{
"type": "Plantain",
"quant": 5
}
]
},
{
"Orange": [
{
"type": "Blood",
"quant": 3
},
{
"type": "Navel",
"quant": 20
}
]
}
]
}
My sample Python code is as follows:
import simplejson as json
# Open file
fjson = open('/home/teg/projects/test/fruits.json', 'rb')
f = json.loads(fjson.read())
fjson.close()
# Search for fruit
if 'Orange' in json.dumps(f):
fruit = f['fruits']['Orange']
print(fruit)
else:
print('Orange does not exist')
But whenever I test it out, it gives me this error:
TypeError: list indices must be integers, not str
Was it wrong to have me do a json.dumps and instead should I have just checked the JSON feed as-is from the standard json.loads? I am getting this TypeError because I am not specifying the list index, but what if I don't know the index of that fruit?
Do I have to first search for a fruit and if it is there, get the index and then reference the index before the fruit like this?
fruit = f['fruits'][2]['Orange']
If so, how would I get the index of that fruit if it is found so I could then pull in the information? If you think the JSON is in the wrong format as well and is causing this issue, then I am up for that suggestion as well. I'm stuck on this and any help you guys have would be great. :-)
Your f type is list, it's a list of dictionary's with sub dictionary.
if 'Orange' in json.dumps(f): Will iterate the list and look at each item for Orange.
The problem is that f['fruits'] is a list so it expects an int number (place)
and not a dictionary key like ['Orange']
I think you should check your structure like #kindall said, if you still want to extract Orange this code will do the trick:
for value in f['fruits']:
if 'Orange' in value:
print value['Orange']
The problem is that the data structure has a list enclosing the dictionaries. If you have any control over the data source, that's the place to fix it. Otherwise, the best course is probably to post-process the data after parsing it to eliminate these extra list structures and merge the dictionaries in each list into a single dictionary. If you use an OrderedDict you can even retain the ordering of the items (which is probably why the list was used).
The square bracket in the line "fruits": [ should tell you that the item associated with fruits is (in Python parlance) a list rather than a dict and so cannot be indexed directly with a string like 'Oranges'. It sounds like you want to create a dict of fruits instead. You could do this by reformatting the input.
Or, if the input format is fixed: each item in your fruits list currently has a very specific format. Each item is a dict with exactly one key, and those keys are not duplicated between items. If those rules can be relied upon, it's pretty easy to write a small search routine—or the following code will convert a list-of-dicts into a dict:
fruits = dict(sum([x.items() for x in f['fruits']], []))
print fruits['Orange']