Related
I have a large script that parses js with a dataframe entry, but to shorten the question, I put what I need in a separate variable.
My variable contains the following value
value = "{from:[3,4],to:[7,4],color:2},{from:[3,6],to:[10,6],color:3}"
I apply the following script and get data like this
value = "{from:[3,4],to:[7,4],color:2},{from:[3,6],to:[10,6],color:3}"
def parse_json(value):
arr = value.split("},")
arr = [x+"}" for x in arr]
arr[-1] = arr[-1][:-1]
return json.dumps({str(i):add_quotation_marks(x) for i, x in enumerate(arr)})
def add_quotation_marks(value):
words = re.findall(r'(\w+:)', value)
for word in words:
value = value.replace(word[:-1], f'"{word[:-1]}"')
return json.loads(value)
print(parse_json(value))
{"0": {"from": [3, 4], "to": [7, 4], "color": 2}, "1": {"from": [3, 6], "to": [10, 6], "color": 3}}
The script executes correctly, but I need to get a slightly different result.
This is what the result I want to get looks like:
{
"0": {
"from": {
"0": "3",
"1": "4"
},
"to": {
"0": "7",
"1": "4"
},
"color": "2"
},
"1": {
"from": {
"0": "3",
"1": "6"
},
"to": {
"0": "10",
"1": "6"
},
"color": "3"
}
}
This is valid json and valid yaml. Please tell me how can I do this
I'd suggest a regex approach in this case:
res = []
# iterates over each "{from:...,to:...,color:...}" group separately
for obj in re.findall(r'\{([^}]+)}', value):
item = {}
# iterates over each "...:..." key-value separately
for k, v in re.findall(r'(\w+):(\[[^]]+]|\d+)', obj):
if v.startswith('['):
v = v.strip('[]').split(',')
item[k] = v
res.append(item)
This produces this output in res:
[{'from': ['3', '4'], 'to': ['7', '4'], 'color': '2'}, {'from': ['3', '6'], 'to': ['10', '6'], 'color': '3'}]
Since your values can contain commas, trying to split on commas or other markers is fairly tricky, and using these regexes to match your desired values instead is more stable.
Here's the code that converts the the value to your desired output.
import json5 # pip install json5
value = "{from:[3,4],to:[7,4],color:2},{from:[3,6],to:[10,6],color:3}"
def convert(str_value):
str_value = f"[{str_value}]" # added [] to make it a valid json
parsed_value = json5.loads(str_value) # convert to python object
output = {} # create empty dict
# Loop through the list of dicts. For each item, create a new dict
# with the index as the key and the value as the value. If the value
# is a list, convert it to a dict with the index as the key and the
# value as the value. If the value is not a list, just add it to the dict.
for i, d in enumerate(parsed_value):
output[i] = {}
for k, v in d.items():
output[i][k] = {j: v[j] for j in range(len(v))} if isinstance(v, list) else v
return output
print(json5.dumps(convert(value)))
Output
{
"0": {
"from": {
"1": 4
},
"to": {
"0": 7,
"1": 4
},
"color": 2
},
"1": {
"from": {
"0": 3,
"1": 6
},
"to": {
"0": 10,
"1": 6
},
"color": 3
}
}
json5 package allows you to convert a javascrip object to a python dictionary so you dont have to do split("},{").
Then added [ and ] to make the string a valid json.
Then load the string using json5.loads()
Now you can loop through the dictionary and convert it to desired output format.
I have a line like this and I need to convert it to json format
{from:[3,4],to:[7,4],color:2},{from:[3,6],to:[10,6],color:3},{from:[5,8],to:[9,8],color:5},{from:[5,11],to:[10,11],color:6},{from:[1,0],to:[1,11],color:0},{from:[10,1],to:[10,6],color:4},{from:[3,0],to:[8,0],color: 1}
Applying this code, I will transform it, but not completely, as I need
def select(value):
ll = value.split(',{')
ll = [element.replace("{", '') for element in ll]
ll = [element.replace("}", '') for element in ll]
js = {str(i):letter for i,letter in enumerate(ll)}
js = json.dumps(js)
return js
total["data_words_selection"] = total["data_words_selection"].map(lambda x: str(x).lstrip("['").rstrip("']")).astype(str)
total['data_words_selection'] = total['data_words_selection'].apply(select)
I receive it like this:
{
"0": "from:[3,4],to:[7,4],color:2",
"1": "from:[3,6],to:[10,6],color:3",
"2": "from:[5,8],to:[9,8],color:5",
"3": "from:[5,11],to:[10,11],color:6",
"4": "from:[1,0],to:[1,11],color:0",
"5": "from:[10,1],to:[10,6],color:4",
"6": "from:[3,0],to:[8,0],color:1"
}
I get valid json. Please tell me how can I convert this string to this format:
{
"0":
"from":
"0": "3"
"1": "4"
"to":
"0": "7"
"1": "4"
"color": "2"
"1":
"from":
"0": "3"
"1": "6"
"to":
"0": "10"
"1": "5"
"color": "3"
}
The result, which I would like to see, was written by hand, sorry for the mistakes. please tell me
This is an example of what it should look like. I hope you understand what I want
As other guys said. It is not perfectly clear what you want to do. But maybe this code can help you:
import json
import re
input_ = "{from:[3,4],to:[7,4],color:2},{from:[3,6],to:[10,6],color:3},{from:[5,8],to:[9,8],color:5},{from:[5,11],to:[10,11],color:6},{from:[1,0],to:[1,11],color:0},{from:[10,1],to:[10,6],color:4},{from:[3,0],to:[8,0],color:1}"
def parse_json(input_):
arr = input_.split("},")
arr = [x+"}" for x in arr]
arr[-1] = arr[-1][:-1]
return json.dumps({str(i):add_quotation_marks(x) for i, x in enumerate(arr)})
def add_quotation_marks(input_):
words = re.findall(r'(\w+:)', input_)
for word in words:
input_ = input_.replace(word[:-1], f'"{word[:-1]}"')
return json.loads(input_)
print(parse_json(input_))
List stay as list, but it could be transformed into dict.
I have 2 lists from these two lists i have to place values in multiple rows
data is json file in which these values need to be placed
listA = [A,B,C,D]
listB = [11,12,13,14]
Result I would like to see as in json file as
"A" : [{
section = 11
}],
"B" : [{
section = 12
}]'
"C" : [{
section = 13
}]
"D" : [{
section = 14
}]
but currently i am getting as below
"A" : [{
section = 14
}],
"B" : [{
section = 14
}]'
"C" : [{
section = 14
}]
"D" : [{
section = 14
}]
The code i am using is below,here data is main json file where i need to place value
for j in listA:
for k in listB:
if j == 'A' :
data[j][0]["section"] = str(k)
elif j == 'B':
data[j][0]["section"] = str(k)
elif j == 'C' :
data[j][0]["section"] = str(k)
elif j == 'D' :
data[j][0]["section"] = str(k)
I hope I've understood your question well. If you have data in this format:
data = {
"A": [{"section": ""}],
"B": [{"section": ""}],
"C": [{"section": ""}],
"D": [{"section": ""}],
}
Then you can use zip() to iterate over listA and listB simultaneously:
listA = ["A", "B", "C", "D"]
listB = [11, 12, 13, 14]
for a, b in zip(listA, listB):
data[a][0]["section"] = b
print(data)
Prints:
{
"A": [{"section": 11}],
"B": [{"section": 12}],
"C": [{"section": 13}],
"D": [{"section": 14}],
}
I'll just go straight to example:
Here we have a dictionary with a test name, and another dict which contains the level categorization.
EDIT
Input:
test_values={
{
"name":"test1",
"level_map":{
"system":1,
"system_apps":2,
"app_test":3
}
},
{
"name":"test2",
"level_map":{
"system":1,
"system_apps":2,
"app_test":3
}
},
{
"name":"test3",
"level_map":{
"system":1,
"memory":2,
"memory_test":3
}
}
}
Output:
What I want is this:
dict_obj:
{
"system":{
"system_apps":{
"app_test":{
test1 object,
test2 object
},
"memory":{
"memory_test":{
test3 object
}
}
}
}
I just can't wrap my head around the logic and I'm struggling to even come up with an approach. If someone could guide me, that would be great.
Let's start with level_map. You can sort keys on values to get the ordered levels:
>>> level_map = { "system": 1, "system_apps": 2, "app_test": 3}
>>> L = sorted(level_map.keys(), key=lambda k: level_map[k])
>>> L
['system', 'system_apps', 'app_test']
Use these elements to build a tree:
>>> root = {}
>>> temp = root
>>> for k in L[:-1]:
... temp = temp.setdefault(k, {}) # create new inner dict if necessary
...
>>> temp.setdefault(L[-1], []).append("test") # and add a name
>>> root
{'system': {'system_apps': {'app_test': ['test']}}}
I split the list before the last element, because the last element will be associated to a list, not a dict (leaves of the tree are lists in your example).
Now, the it's easy to repeat this with the list of dicts:
ds = [{ "name": "test1",
"level_map": { "system": 1, "system_apps": 2, "app_test": 3}
}, { "name": "test2",
"level_map": { "system": 1, "system_apps": 2, "app_test": 3}
}, { "name": "test3",
"level_map": { "system": 1, "memory": 2, "memory_test": 3}
}]
root = {}
for d in ds:
name = d["name"]
level_map = d["level_map"]
L = sorted(level_map.keys(), key=lambda k: level_map[k])
temp = root
for k in L[:-1]:
temp = temp.setdefault(k, {})
temp.setdefault(L[-1], []).append(name)
# root is: {'system': {'system_apps': {'app_test': ['test1', 'test2']}, 'memory': {'memory_test': ['test3']}}}
I want to create a script where I check a json file times to times using a while function. In there there is a json that looks like:
{
"names":[
{
"name":"hello",
"numbers":0
},
{
"name":"stack",
"numbers":1
},
{
"name":"over",
"numbers":2
},
{
"name":"flow",
"numbers":12
},
{
"name":"how",
"numbers":17
},
{
"name":"are",
"numbers":11
},
{
"name":"you",
"numbers":18
},
{
"name":"today",
"numbers":6
},
{
"name":"merry",
"numbers":4
},
{
"name":"x",
"numbers":1
},
{
"name":"mass",
"numbers":0
},
{
"name":"santa",
"numbers":4
},
{
"name":"hohoho",
"numbers":1
}
]
}
and what I want to do is that I want to check every number if numbers for each name has been increased than previous json look.
def script():
with open('data.json') as f:
old_data = json.load(f)
while True:
with open('data.json') as f:
new_data = json.load(f)
if old_data < new_data:
print("Bigger!!" + new_data['name'])
old_data = new_data
else:
randomtime = random.randint(5, 15)
print("Nothing increased")
old_data = new_data
time.sleep(randomtime)
Now I know that I have done it wrong and that's the reason I am here. I have no idea at this moment what I can do to make a sort of function where it checks numbers by numbers to see if its gotten bigger or not.
My question is:
How can I make it so it checks object by object to see if the numbers has gotten bigger from previous loop? and if it has not gotten bigger but lower, it should update the value of old_data and loops forever until the numbers has gotten bigger than previous loop?
EDIT:
Recommendation that I got from #Karl
{
'names': {
'hello': 0,
'stack': 0,
'over': 2,
'flow': 12,
'how': 17,
'are': 11,
'you': 18,
'today': 6,
'merry': 4,
'x': 1,
'mass': 0,
'santa': 4,
'hohoho': 1
}
}
Assuming your json is in this format:
{
"names": {
"hello": 0,
"stack": 1,
"over": 2,
"flow": 13,
"how": 17,
"are": 12,
"you": 18,
"today": 6,
"merry": 4,
"x": 1,
"mass": 0,
"santa": 4,
"hohoho": 1
}
}
I would do something along the following lines:
import json
import time
with open("data.json") as f:
old_data = json.load(f)["names"]
while True:
with open("data.json") as f:
new_data = json.load(f)["names"]
for name, number in new_data.items():
if number > old_data[name]:
print("Entry '{0}' has increased from {1} to {2}".format(name, old_data[name], number))
old_data = new_data
print("sleeping for 5 seconds")
time.sleep(5)
EDIT to answer question posted in comment "just curious, lets say if I want to add another value beside the numbers etc "stack": 1, yes (Yes and no to each of format), What would be needed to do in that case? (Just a script that I want to develop from this)".
In that case you should design your json input as follows:
{
"names": {
"hello": {
"number": 0,
"status": true
},
"stack": {
"number": 1,
"status": true
},
"over": {
"number": 2,
"status": false
},
...
}
}
You would need to change the lookups in the comparison script as follows:
for name, values in new_data.items():
if values["number"] > old_data[name]["number"]
(Note that for status you could also just have "yes" or "no" as inputs, but using booleans is must more useful when you have to represent a binary choice like this).
By the way, unless you aim to have objects other than names in this json, you can leave out that level and just make it:
{
"hello": {
"number": 0,
"status": true
},
"stack": {
"number": 1,
"status": true
},
"over": {
"number": 2,
"status": false
},
...
}
In that case, replace old_data = json.load(f)["names"] with old_data = json.load(f) and new_data= json.load(f)["names"] with new_data= json.load(f)
I took your original .json which you edited and presented in your question and re-factored your code to the below example. It appears to be working.
import time
import random
import json
path_to_file = r"C:\path\to\.json"
def script():
with open(path_to_file) as f:
d = json.load(f)
old_data = 0
for a_list in d.values():
for i in a_list:
print()
for d_keys, d_values in i.items():
print(d_keys, d_values)
if type(d_values) == int and d_values > old_data:
print("Bigger!!" + i['name'])
old_data = d_values
elif type(d_values) == int and d_values < old_data:
print("Nothing increased")
old_data = d_values
randomtime = random.randint(5, 15)
time.sleep(randomtime)
script()
This is the output I receive:
name hello numbers 0
name stack numbers 1 Bigger!!stack
name over numbers 2 Bigger!!over
name flow numbers 12 Bigger!!flow
name how numbers 17 Bigger!!how
name are numbers 11 Nothing increased
name you numbers 18 Bigger!!you
name today numbers 6 Nothing increased
name merry numbers 4 Nothing increased
name x numbers 1 Nothing increased
name mass numbers 0 Nothing increased
name santa numbers 4 Bigger!!santa
name hohoho numbers 1 Nothing increased