I have been using Mathematica to analyse some data from the StackExchange API. It is conveniently available in JSON form, which Mathematica interprets as replacement rules. However, some of the rules are nested as the right-hand side of an outer rule, as you can see in the case of badge_counts
here:
Import["http://api.stackexchange.com/2.0/users?page=1&order=desc&sort=reputation&site=mathematica",
"JSON"][[2, 2, 10]]
(* Out[1]=
{"accept_rate" -> 75, "account_id" -> 395497, "age" -> 41,
"badge_counts" -> {"bronze" -> 35, "gold" -> 0, "silver" -> 11},
"creation_date" -> 1326833982, "display_name" -> "Verbeia",
"is_employee" -> False, "last_access_date" -> 1331949804,
"last_modified_date" -> 1330990001,
"link" -> "http://mathematica.stackexchange.com/users/8/verbeia",
"location" -> "Sydney, Australia",
"profile_image" -> "http://www.gravatar.com/avatar/3df2379fc0221bb0281c0d608542bd84?d=\identicon&r=PG",
"reputation" -> 3571, "reputation_change_day" -> 0,
"reputation_change_month" -> 857,
"reputation_change_quarter" -> 3475, "reputation_change_week" -> 605,
"reputation_change_year" -> 3475, "user_id" -> 8,
"user_type" -> "registered",
"website_url" -> "http://www.verbeia.com/mathematica"}
*)
Users without any badges don't have this nested rule. To handle both cases I am doing something like this to get the badge counts in a flattened list, so each row of the final list corresponds to a user of the site:
getUserData[page_Integer] := Module[{ad},
ad = Import[
"http://api.stackexchange.com/2.0/users?page=" <>
IntegerString[page] <>
"&order=desc&sort=reputation&site=mathematica", "JSON"][[2,2]];
If[Length[ad] > 0,
Join[Most[#], {"bronze", "silver", "gold"} /.
Last[#]] & /@ (({"display_name", "creation_date", "reputation",
"reputation_change_week", "is_employee", "last_access_date",
"user_type", "badge_counts"} /. ad) /.
"badge_counts" -> {"bronze" -> 0, "silver" -> 0,
"gold" -> 0}), {}]
]
Which I can then build up into a list of all users and their stats like this:
Monitor[
pageM = 0;
resultM =
FixedPoint[Join[#, getUserData[++pageM]] &, {}];,
StringForm["Loading page `` ...", pageM]
]
The final output is list of vectors that look like this:
resultM[[10]]
(*Out[2]= {"Verbeia", 1326833982, 3571, 605, False, 1331949804, "registered", 35, 11, 0} *)
My question is: is there a more concise or elegant way to write the getUserData
function, without need a Join
and three separate ReplaceAll
(/.
) constructions?