0
\$\begingroup\$

I have a sample Json as mentioned below

[{
    "Name": "Kim",
    "Details": {
        "Age": 43,
        "Gender": "Male",
        "Education": [{
                "Primary": "Xavier",
                "Percentage": 90,
                "subject": [{
                        "sub": "Math",
                        "Perf": "Good"
                    },
                    {
                        "sub": "Sci",
                        "Perf": "Averge"
                    }, {
                        "sub": "Eco",
                        "Perf": "Good"
                    }
                ],
                "Marks": [{
                        "Mark": 90,
                        "Grade": "A"

                    },
                    {
                        "Mark": 92,
                        "Grade": "S"
                    }, {
                        "Mark": 80,
                        "Grade": "B"
                    }
                ]
            },
            {
                "Seconday": "Anthony",
                "Percentage": 98,
                "subject": [{
                    "sub": "Math",
                    "Perf": "Good"
                }],
                "Marks": [{
                    "Mark": 100,
                    "Grade": "S"
                }]
            },
            {
                "Bachelor": "Boston",
                "Percentage": 90,
                "subject": [{
                    "sub": "Computers",
                    "Perf": "Good"
                }],
                "Marks": [{
                    "Mark": 90,
                    "Grade": "A"
                }]
            },
            {

                "PostGrad": "Boston",
                "Percentage": 90,
                "subject": [{
                    "sub": "CNN",
                    "Perf": "Good"
                }],
                "Marks": [{
                    "Mark": 90,
                    "Grade": "A"
                }]
            }]
    }
}]

form this I need to fetch the sub and Mark only from the entire Json.

I got the necessary output but the concern is I have utilised multiple for loops, below mentioned is my approch to fetch sub and marks,

import json
sampleJson = open('C:\\Users\\SampleJson.json')
sampleJsonData = json.loads(sampleJson.read())

resArray=[]
for i in range(len(sampleJsonData)):
    for j in range(len(sampleJsonData[i]["Details"])):
       for k in range(len(sampleJsonData[i]["Details"]["Education"])):
           for l in range(len(sampleJsonData[i]["Details"]["Education"])):
                for y in range(len(sampleJsonData[i]["Details"]["Education"][l]["subject"])):
                    sub = (sampleJsonData[i]["Details"]["Education"][l]["subject"][y]["sub"])
                for z in range(len(sampleJsonData[i]["Details"]["Education"][l]["Marks"])):
                    marks = sampleJsonData[i]["Details"]["Education"][l]["Marks"][z]["Mark"]
                    

by any means is there any possibility that I could reduce the usage of for loops to nil.

I need to use those sub and Mark values further, as a temp measure stored the values in different variables.

I'm relatively very new to python, Please help me on this. Thanks

New contributor
devPie is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
4
  • 3
    \$\begingroup\$ Just curios, what is the desired output? I got an empty list of your code. Do you want 'Math', 'Sci', 'Eco', 90, 92, 80, 'Math', 100, 'Computers', 90, 'CNN', 90 instead? \$\endgroup\$ Jan 10 at 20:47
  • 2
    \$\begingroup\$ Welcome to Code Review! Please edit your question so that the title describes the purpose of the code, rather than its mechanism. We really need to understand the motivational context to give good reviews. Thanks! \$\endgroup\$ Jan 10 at 21:19
  • \$\begingroup\$ (There is a resArray, sub and marks that I don't see used. There is a lot of common (sub-)expressions ("subscripting").) \$\endgroup\$
    – greybeard
    Jan 10 at 22:20
  • 1
    \$\begingroup\$ How do you need to use sub and mark further? Do you just need those values in a list, like Thingamabobs showed? Do you need separate lists of subs and marks, which your variable names suggest? Do you need only that portion of the json? Do you need a dict of {sub:mark} for each (and if so, how should the subs from Xavier match up to the marks)? You keep overwriting your assignments to sub and marks, and you never touch resArray. \$\endgroup\$
    – Teepeemm
    Jan 10 at 23:46
10
\$\begingroup\$

At a wild guess, it seems like you want to perform a flattening operation. Your current code definitely hasn't done it correctly, and it's not even clear what "correct" is; but if you

  • replace your loads with a load;
  • use a with on your file;
  • get rid of all your numerical indices, and
  • use a nested list comprehension on your dictionary,

you can produce a list of subject-mark tuples:

from pprint import pprint
import json

with open('272857.json') as sample_json:
    sample_json_data = json.load(sample_json)

res_array = [
    (subject['sub'], marks['Mark'])
    for person in sample_json_data
    for education in person['Details']['Education']
    for subject, marks in zip(education['subject'], education['Marks'])
]
pprint(res_array)

produces

[('Math', 90),
 ('Sci', 92),
 ('Eco', 80),
 ('Math', 100),
 ('Computers', 90),
 ('CNN', 90)]

I can only assume that it's OK for this to throw out all other information about what education and person the mark came from, etc.

[could I] reduce the usage of for loops to nil

No. Either you, or a library you call, is going to need to loop.

\$\endgroup\$
-1
\$\begingroup\$

Depending on your bigger needs/situation another, completely different, approach you could take is just parse the entire string using regexp's.

So conceptually you're just looking for patterns in a string, ignoring the fact it's json, and any data structure/hierarchy contained within. However, for you needs it may fit perfectly, or it may be completely in appropriate

You could make a couple of regexps to looks for and returns the sub and mark values.

This would:

  1. Not involve any loops at all
  2. Therefore be much, much faster

Of course, it would also:

  1. Be completely unable to handle any data grouping, hierarchy or structure
  2. Be harder (somewhat) to maintain, extend or explain
  3. Not as clean or simple from a code perspective

But, for you particular needs/situation/priorities this may or may not be a valid approach.

New contributor
Richard is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Regex matching of the rendered string in JSON is really not a good idea. Parsing of the container format should be left to an established JSON module. \$\endgroup\$
    – Reinderien
    Jan 11 at 17:46
  • \$\begingroup\$ @Reinderien Agree! ...not saying it's necessarily a good idea (though you can easily put together a regexp that doesn't require the JSON to be 'rendered`), and in general way better to leave the parsing to the container itself. ...but it is an option that would work, and so in some cases may be a better fit. Eg if you're absolute highest requirement is speed. \$\endgroup\$
    – Richard
    Jan 11 at 18:33

Your Answer

devPie is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.