messy json file is parsed and should output the N highest record IDs & scores by score in descending order, highest score first.
the code works but i wonder if there is better readability, help me refactor it.
The function takes 2 args - the data file path and num of scores to return:
python myprogram.py highest score_recs.data 25
The input data file has a record per line. Each line has the following structure:
<score>: <json string>
If the line has a score that would make it part of the highest scores, then the remainder of the line must be parsable as JSON, and there must be an id key at the top level of this JSON doc.
An example data file could look like this:
10622876: {"umbrella": 99180, "name": "24490249af01e145437f2f64d5ddb9c04463c033", "value": 12354, "payload": "........", "date_stamp": 58874, "time": 615416, "id": "3c867674494e4a7aac9247a9d9a2179c"}
13214012: {"umbrella": 924902, "name": "70dd4d9494d1cd0362e123ce90f4053726b29e97", "value": 976852, "payload": "........", "date_stamp": 3255, "time": 156309, "id": "085a11e1b82b441184f4a193a3c9a13c"}
11446512: {"umbrella": 727371, "name": "8e21427b2350023079835361dce03cdea95a2983", "value": 70801, "payload": "........", "date_stamp": 1730, "time": 496866, "id": "84a0ccfec7d1475b8bfcae1945aea8f0"}
11025835: === THIS IS NOT JSON and should error
11269569: {"umbrella": 902167, "name": "e4898b9bf79831cf36811917a797ef0fcf3af636", "value": 593180, "payload": "........", "date_stamp": 58736, "time": 1014495, "id": "7ec85fe3aa3c4dd599e23111e7abf5c1"}
11027069: {"umbrella": 990975, "name": "8aa306fb59e275a7e39debb1d5113ff411df22ad", "value": 67842, "payload": "........", "date_stamp": 60161, "time": 225413, "id": "f812d487de244023a6a713e496a8427d"}
initially json file is not sorted by scores.
steps:
- the bad json error is thrown only if there is bad record within the first minimum n unsorted lines,i.e. in the original json
- otherwise, even if there is bad record but not within the first n unsorted lines i can keep all the records and parse it
- sort it by scores in desc order, then keep the first n output a list of dicts, each dict has 2 fields - score,id
For example, if run with an N of 3 and 4th entry is bad json, it still works and produce:
python myprogram highest score_recs.data 3
[
{
"score": 13214012,
"id": "085a11e1b82b441184f4a193a3c9a13c"
},
{
"score": 11446512,
"id": "84a0ccfec7d1475b8bfcae1945aea8f0"
},
{
"score": 11269569,
"id": "7ec85fe3aa3c4dd599e23111e7abf5c1"
}
]
But when run with an N that includes that line, it would error:
$ python myprogram highest score_recs.data 10
invalid json format No JSON object could be decoded
THIS IS NOT JSON
The scores are unique across the data set * Scores can repeat, but you should only count the id of the last line processed as the “winning” id. if score is not present it should give format error.
scores.data:
10622876: {"umbrella": 99180, "name": "24490249af01e145437f2f64d5ddb9c04463c033", "value": 12354, "payload": "........", "date_stamp": 58874, "time": 615416, "id": "3c867674494e4a7aac9247a9d9a2179c"}
13214012: {"umbrella": 924902, "name": "70dd4d9494d1cd0362e123ce90f4053726b29e97", "value": 976852, "payload": "........", "date_stamp": 3255, "time": 156309, "id": "085a11e1b82b441184f4a193a3c9a13c"}
11446512: {"umbrella": 727371, "name": "8e21427b2350023079835361dce03cdea95a2983", "value": 70801, "payload": "........", "date_stamp": 1730, "time": 496866, "id": "84a0ccfec7d1475b8bfcae1945aea8f0"}
11025835: === THIS IS NOT JSON and should error if this line is part of the result set, but is ok if it not ==
11269569: {"umbrella": 902167, "name": "e4898b9bf79831cf36811917a797ef0fcf3af636", "value": 593180, "payload": "........", "date_stamp": 58736, "time": 1014495, "id": "7ec85fe3aa3c4dd599e23111e7abf5c1"}
11027069: {"umbrella": 990975, "name": "8aa306fb59e275a7e39debb1d5113ff411df22ad", "value": 67842, "payload": "........", "date_stamp": 60161, "time": 225413, "id": "f812d487de244023a6a713e496a8427d"}
the python code:
import json
import sys
def main(filename, n):
res = []
main = dict()
cnt = 1
with open(filename, "r") as f:
for line in f:
id, content = line.split(":", 1)
try:
id = int(id)
except ValueError:
raise "Format error - no id"
if "IS NOT JSON" in content:
print("found bad json - check if we can continue")
if cnt <= n:
# here this means the original unsorted json file has bad json within the first needed n lines - so we need to throw error as per the condition
raise "ERROR: THIS IS NOT JSON"
else:
print("ah no, its good")
else:
try: # need try here cuz when json.loads() sees bad json - it will throw jsondecode error, that i need to catch
newd = json.loads(content)
main[id] = newd
cnt += 1
except:
print(
"keep pushing! that bad json is after the minimum n we need - so we need to record all jsons then sort then get the first n"
)
main = [[k, v] for k, v in main.items()]
main = sorted(main, reverse=True, key=lambda x: x[0])
#get the first sorted n items, create a dict [score][id]
main = dict(main[:n])
for k, v in main.items():
score = k
id = v["id"]
newd = dict()
newd["score"] = score
newd["id"] = id
res.append(newd)
return res
arg_list = (sys.argv)
filenamepath = str(arg_list[1])
num_lines = int(arg_list[2])
main(filenamepath, num_lines)