How to change the value of a JSON list? - python

I know for fact that this question has been asked before. I looked at the following posts:
Python replace values in unknown structure JSON file
How to find and replace a part of a value in json file
https://pretagteam.com/question/how-to-replace-a-value-in-json-file-using-python
How to find and replace a part of a value in json file (Somehow this is what I am looking for but it does not fit my problem with the links being different and stored all under "latest")
and much more contributions, however I am still stuck.
I have a simple JSON structure like this:
{
"guild1": {
"latest": [
"link1",
"link2"
],
"channel": channel_here
},
"guild2": {
"latest": [
"link"
],
"channel": channel_here
}
}
I found a way to iterate over the entries and print the list in which the condition is found, for example:
# searching for link 1
["link1", "link2", "link3"] # here link 1 for example is found in one of the list entries
["link5"] -> This for example does not match what I am looking for, I can ignore this
If found, I simply want to replace it (just link1) with another before defined value. I tried to iterate over the keys of the found list but was not able to .replace it or something else. The key which matches my search criteria is printed out, but I can't do anything else with it. Is it even possible to change the entry in a list that easy?
Mostly I also got the following error which I also looked up but did not get any did not get any wiser:
TypeError: string indices must be integers
Here is how I search for the list end the "entries":
if defined_link in data[searchloop]['latest']: # data is my JSON file, searchloop the for-loop
for key in data[searchloop]['latest']: # Get all the matching keys
if key == defined_link: # Get the key I am looking for
Maybe someone else can help me here!

This code would change one value in a list (here 'link1') to another:
L = ["link1", "link2", "link3"]
L[L.index('link1')] = 'someOtherValue'
After this you would see that L changed to ["someOtherValue", "link2", "link3"]
You first find at which index is 'link1', let's say you get back 3. So, you know you have to change the value of L[3]. Now it's simple. Do L[3] = 'someOtherValue'.

Iterate over each guild in the json structure.
Iterate over each link in that guild's "latest" list.
If the link matches, assign that list item to something else.
for guild in jsonstructure:
for i in range(len(jsonstructure[guild]['latest'])):
if jsonstructure[guild]['latest'][i] == 'something':
jsonstructure[guild]['latest'][i] = 'new thing'

I think you should try
list.append(i)
It will work I faced same problem
For example:
string = "Hello World!"
list = []
for i in string:
list.append(string[i])
print(list)

Related

I can't get a value from a JSON API response in python

So I am struggling with getting a value from a JSON response. Looking in other post I have managed to write this code but when I try to search for the key (character_id) that I want in the dictionary python says that the key doesn't exist. My solution consists in getting the JSON object from the response, converting it into a string with json.dumps() and the converting it into a dictionary with json.loads(). Then I try to get 'character_id' from the dictionary but it doesn't exist. I am guessing it is related with the format of the dictionary but I have little to none experience in python. The code that makes the query and tries to get the values is this: (dataRequest is a fuction that makes the request and return the response from the api)
characterName = sys.argv[1];
response = dataRequest('http://census.daybreakgames.com/s:888/get/ps2:v2/character/?name.first_lower=' + characterName + '&c:show=character_id')
jsonString = json.dumps(response.json())
print(jsonString)
dic = json.loads(jsonString)
print(dic)
if 'character_id' in dic:
print(dic['character_id'])
The output of the code is:
{"character_list": [{"character_id": "5428662532301799649"}], "returned": 1}
{'character_list': [{'character_id': '5428662532301799649'}], 'returned': 1}
Welcome #Prieto! From what I can see, you probably don't need to serialize/de-serialize the JSON -- response.json() returns a python dictionary object already.
The issue is that you are looking for the 'character_id' key at the top-level of the dictionary, when it seems to be embedded inside another dictionary, that is inside a list. Try something like this:
#...omitted code
for char_obj in dic["character_list"]:
if "character_id" in char_obj:
print(char_obj["character_id"])
if your dic is like {"character_list": [{"character_id": "5428662532301799649"}], "returned": 1}
you get the value of character_id by
print(dic['character_list'][0][character_id])
The problem here is that you're trying to access a dictionary where the key is actually character_list.
What you need to do is to access the character_list value and iterate over or filter the character_id you want.
Like this:
print(jsonString)
dic = json.loads(jsonString)
print(dic)
character_information = dic['character_list'][0] # we access the character list and assume it is the first value
print(character_information["character_id"]) # this is your character id
The way I see it, the only hiccup with the code is this :
if 'character_id' in dic:
print(dic['character_id'])
The problem is that, the JSON file actually consists of actually 2 dictionaries , first is the main one, which has two keys, character_list and returned. There is a second sub-dictionary inside the array, which is the value for the key character_list.
So, what your code should actually look like is something like this:
for i in dic["character_list"]:
print(i["character_id"])
On a side-note, it will help to look at JSON file in this way :
{
"character_list": [
{
"character_id": "5428662532301799649"
}
],
"returned": 1
}
,where, elements enclosed in curly-brackets'{}' imply they are in a dictionary, whereas elements enclosed in curly-brackets'[]' imply they are in a list

Accessing Nested JSON [AWS Metadata] with Python

I'm using Lambda to run through my AWS account, returning a list of all instances. I need to be able to print out all of the 'VolumeId' values, but I can't work out how to access them as they are nested. I am able to print out the first VolumeId for each instance, however, some of the instances have several volumes, and some only have one. I think I know why I get these results, but I can't work out what to do to get all of them back.
Here's a snippet of what the JSON for one instance looks like:
{
'Groups':[],
'Instances':[
{
'AmiLaunchIndex':0,
'ImageId':'ami-0',
'InstanceId':'i-0123',
'InstanceType':'big',
'KeyName':'nonprod',
'LaunchTime':'date',
'Monitoring':{
'State':'disabled'
},
'Placement':{
'AvailabilityZone':'world',
'GroupName':'',
'Tenancy':'default'
},
'PrivateDnsName':'secret',
'PrivateIpAddress':'1.2.3.4',
'ProductCodes':[
],
'PublicDnsName':'',
'State':{
'Code':80,
'Name':'stopped'
},
'StateTransitionReason':'User initiated',
'SubnetId':'subnet-1',
'VpcId':'vpc-1',
'Architecture':'yes',
'BlockDeviceMappings':[
{
'DeviceName':'/sda',
'Ebs':{
'AttachTime':'date',
'DeleteOnTermination':True,
'Status':'attached',
'VolumeId':'vol-1'
}
},
{
'DeviceName':'/sdb',
'Ebs':{
'AttachTime':'date'),
'DeleteOnTermination':False,
'Status':'attached',
'VolumeId':'vol-2'
}
}
],
This is what I'm doing to get the first VolumeId:
ec2client = boto3.client('ec2')
ec2 = ec2client.describe_instances()
for reservation in ec2["Reservations"]:
for instance in reservation["Instances"]:
instanceid = instance["InstanceId"]
volumes = instance["BlockDeviceMappings"][0]["Ebs"]["VolumeId"]
print("The associated volume IDs for this instance are: ",(volumes))
I think the reason that I'm getting just the first ID is because I'm referencing the first element within "BlockDeviceMappings", but I can't work out how to get the other ones. If I try it without specifying the [0], I get the list indices must be integers or slices, not str error. I tried to use a dictionary instead of a list too, but felt like I was barking up the wrong tree with that one. Any suggestions/help would be appreciated!
One possible answer, not particularly pythonic
...
id_list = []
volumes_data = instance["BlockDeviceMappings"]
for element in volumes_data:
id_list.append(element["Ebs"]["VolumeId"])
Or else use json.loads and then iterate though json using .get syntax like the final answer in this

How to iterate and extract data from this specific JSON file example

I'm trying to extract data from a JSON file with Python.
Mainly, I want to pull out the date and time from the "Technicals" section, to put that in one column of a dataframe, as well as pulling the "AKG" number and putting that in the 2nd col of the dataframe. Yes, I've looked at similar questions, but this issue is different. Thanks for your help.
A downNdirty example of the JSON file is below:
{ 'Meta Data': { '1: etc'
'2: etc'},
'Technicals': { '2017-05-04 12:00': { 'AKG': '64.8645'},
'2017-05-04 12:30': { 'AKG': '65.7834'},
'2017-05-04 13:00': { 'AKG': '63.2348'}}}
As you can see, and what's stumping me, is while the date stays the same the time advances. 'AKG' never changes, but the number does. Some of the relevant code I've been using is below. I can extract the date and time, but I can't seem to reach the AKG numbers. Note, I don't need the "AKG", just the number.
I'll mention: I'm creating a DataFrame because this will be easier to work with when creating plots with the data...right? I'm open to an array of lists et al, or anything easier, if that will ultimately help me with the plots.
akg_time = []
akg_akg = []
technicals = akg_data['Technicals'] #akg_data is the entire json file
for item in technicals: #this works
akg_time.append(item)
for item in technicals: #this not so much
symbol = item.get('AKG')
akg_akg.append(symbol)
pp.pprint(akg_akg)
error: 'str' object has no attribute 'get'
You've almost got it. You don't even need the second loop. You can append the akg value in the first one itself:
for key in technicals: # renaming to key because that is a clearer name
akg_time.append(key)
akg_akg.append(technicals[key]['AKG'])
Your error is because you believe item (or key) is a dict. It is not. It is just a string, one of the keys of the technicals dictionary, so you'd actually need to use symbols = technicals[key].get('AKG').
Although Coldspeed answer is right: when you have a dictionary you loop through keys and values like this:
Python 3
for key,value in technicals.items():
akg_time.append(key)
akg_akg.append(value["akg"])
Python 2
for key,value in technicals.iteritems():
akg_time.append(key)
akg_akg.append(value["akg"])

How do I use a for loop when reading from a dictionary that might contain a list of dicts, but might not?

I apologize in advance that the title is so confusing. It makes a lot more sense in code, so here goes:
I am parsing data from a REST API that returns JSON, and I have a bit of an issue with this particular structure:
{ 'Order' : [
{ 'orderID': '1',
'OrderLines': {
'OrderLine': [
{ 'lineID':'00001', 'quantity':'1', 'cost':'10', 'description':'foo' },
{ 'lineID':'00002', 'quantity':'2', 'cost':'23.42', 'description':'bar' }
]}
}
{ 'orderID': '2',
'OrderLines': {
'OrderLine':
{ 'lineID':'00003', 'quantity':'6', 'cost':'12.99', 'description':'lonely' }
}
}
]}
If you'll notice, the second order only has one OrderLine, so instead of returning a list containing dictionaries, it returns the dictionary. Here is what I am trying to do:
orders_json = json.loads(from_server)
for order in orders_json['Order']:
print 'Order ID: {}'.format(order['orderID'])
for line in order['OrderLines']['OrderLine']:
print '-> Line ID: {}, Quantity: {}'.format(line['lineID'], line['quantity'])
It works just fine for the first order, but the second order throws TypeError: string indices must be integers since line is now a string containing the dictionary, instead of a dictionary from the list. I've been banging my head against this for hours now, and I feel like I am missing something obvious.
Here are some of the things I have tried:
Using len(line) to see if it gave me something unique for the one line orders. It does not. It returns the number of key:value pairs in the dictionary, which in my real program is 10, which an order containing 10 lines would also return.
Using a try/except. Well, that stops the TypeError from halting the whole thing, but I can't figure out how to address the dictionary once I've done that. Line is a string for single line orders instead of a dictionary.
Whoever designed that API did not do a terribly good job. Anyway, you could check whether OrderLine is a list and, if it's not, wrap it in a one-element list before doing any processing:
if not isinstance(order_line, list):
order_line = [order_line]
That would work, my personal preference would be to get the API fixed.
I'd check if the type is correct and then convert it to a list if necessary to have a uniform access:
lines = order['OrderLines']['OrderLine']
lines = [lines] if not isinstance(lines, list) else lines
for line in lines:
...
You can check the type of the object you try to access:
# ...
print 'Order ID: {0}'.format(order['orderID'])
lines = order['OrderLines']['OrderLine']
if isinstance(lines, list):
for line in lines:
print line['lineID']
elif isinstance(lines, dict):
print lines['lineID']
else:
raise ValueError('Illegal JSON object')
Edit: Wrapping the dict in a list as proposed by #NPE is the nicer and smarter solution.

Python parsing json issue

I'm having troubles parsing a complicated json. That is it:
{
"response": {
"players": [
{
"bar": "76561198034360615",
"foo": "49329432943232423"
}
]
}
}
My code:
url = urllib.urlopen("foobar").read()
js = json.load(url)
data = js['response']
print data['players']
The problem is that this would print the dict. What I want is to reach the key's values, like foo and bar. What I tried so far is doing data['players']['foo'] and it gives me an error that list indices should be integers, I tried of course, it didn't work. So my question is how do I reach these values? Thanks in advance.
data['response']['players'] is an array (as defined by the brackets ([, ]), so you need to access items using a specific index (0 in this case):
data['players'][0]['foo']
Or iterate over all players:
for player in data['response']['players']:
print player['foo']
The problem is that players is a list of items ([ ] in json). So you need to select the first and only item in this case using [0].
print data['players'][0]['foo']
But, keep in mind that you may have more than one player, in which case you either need to specify the player, or loop through the players using a for loop
for player in data['players']:
print player['foo']

Categories