Sorting json object by values

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice

Post Reply
User avatar
Irrlicht
Dragon
Posts: 426
Joined: Mon Feb 09, 2009 10:53 am

Sorting json object by values

Post by Irrlicht »

I have a json object with "numeric" (so to say) keys, associated to actual numeric values; example:

{"12":5,"8":9,"21":3}

Since json.sort only works with arrays, how can I order it so that they go from the key with the highest value to the lowest?
For the example, the desired result would be:

{"8":9,"12":5,"21":3}

"8" has the highest value, "12" the second, and "21" the lowest.
"There are many ways my Son, to find where the souls of Demons remain...
But it takes only one second of despair and of doubt until, at last, your Soul they will gain..."

User avatar
aliasmask
RPTools Team
Posts: 9031
Joined: Tue Nov 10, 2009 6:11 pm
Location: California

Re: Sorting json object by values

Post by aliasmask »

You manually deconstruct and rebuild the json object. I'm sure I have some generic code somewhere for this.

Here's a rewrite of json.sort:

Code: Select all

[H: data = arg(0)]
[H, if(argCount() >= 2): direction = arg(1); direction = "a"]
[H, if(json.isEmpty(direction)): direction = "a"; direction = substring(lower(direction),0,1)]
[H, if(json.type(data) == "OBJECT"), code: {
   [H: keys = oldFunction(json.fields(data,"json"),direction)]
   [H: newObj = "{}"]
   [H, foreach(key,keys): newObj = json.set(newObj,key,json.get(data,key))]
};{
   [H: counter = 0]
   [H: args = ""]
   [H, foreach(arg,macro.args), code: {
      [H: args = listAppend(args,"arg"+counter)]
      [H: set("arg"+counter,arg(counter))]
      [H: counter = counter + 1]
   }]
   [H: newObj = eval(strformat("oldFunction(%{args})"))]
}]
[H: macro.return = newObj]

User avatar
Irrlicht
Dragon
Posts: 426
Joined: Mon Feb 09, 2009 10:53 am

Re: Sorting json object by values

Post by Irrlicht »

Thanks for the reply, but I'm not sure how to make it work...

I pasted that code in a macro on a Lib token, and in onCampaignLoad I defined the function "json.sortObjByVal".

Yet, even after reloading, I get:
"Old definition for function json.sortObjByValdoes not exist"

What's wrong?
"There are many ways my Son, to find where the souls of Demons remain...
But it takes only one second of despair and of doubt until, at last, your Soul they will gain..."

User avatar
aliasmask
RPTools Team
Posts: 9031
Joined: Tue Nov 10, 2009 6:11 pm
Location: California

Re: Sorting json object by values

Post by aliasmask »

json.sort is an existing function and my code overwrites it. If you want to make it a separate function just change oldFunction() to json.sort().

User avatar
Irrlicht
Dragon
Posts: 426
Joined: Mon Feb 09, 2009 10:53 am

Re: Sorting json object by values

Post by Irrlicht »

Ah, clear, thanks.

Now, looking at it in haste, from what I understand, it gets the fields and sorts them in an array, then uses that array to retrieve the respective values and create an object. But that object is sorted by fields and not values.

I have a half-idea on how to make it work, but I'm not sure, presently I'm in a hurry, I'll look into it later or tomorrow.
"There are many ways my Son, to find where the souls of Demons remain...
But it takes only one second of despair and of doubt until, at last, your Soul they will gain..."

User avatar
aliasmask
RPTools Team
Posts: 9031
Joined: Tue Nov 10, 2009 6:11 pm
Location: California

Re: Sorting json object by values

Post by aliasmask »

Yep, that's the way I wrote that so I can have my keys in alphabetical order. If you want to sort the object by value and reorder the keys then you can create an array of objects and use the normal json.sort on it then rebuild the object.

Code: Select all

[H: myObj = '{"12":5,"8":9,"21":3}']
[H: myArray = "[]"]
[H, foreach(key,myObj): myArray = json.append(myArray,json.set("{}","key",key,"value",json.get(myObj,key)))]
[H: myArray = json.sort(myArray,"d","value")]
[H: newObj = "{}"]
[H, foreach(obj,myArray): newObj = json.set(newObj,json.get(obj,"key"),json.get(obj,"value"))]
[dialog("D"):{<pre>[R: json.indent(replace(newObj,"<","&lt;"))]</pre>}]
output:

Code: Select all

{
    "8": 9,
    "12": 5,
    "21": 3
}
IMO, the above is shorthand for what the values really mean. ie the key represents something as does the value and should actually be in an array of objects instead of a single object. For example: [{"carNumber":8,"initiative":9},{"carNumber":12,"initiative":5}] I don't know what it actually means, but I think it's something similar.

bobifle
Giant
Posts: 219
Joined: Thu Oct 19, 2017 12:36 pm

Re: Sorting json object by values

Post by bobifle »

Json objects are unordered like most key/value hash tables.

Some solutions may seems to work, but are implementation specific and your object order is subject to change. Especially if you use some java lib in the meantime.

I've not much experience in java/mt, but in python I ran into some very nasty issues, because of the unordered nature of json/dict.

For {"12":5,"8":9,"21":3}

you probably need a function that returns

[{"21":3}, {"12":5},{"8":9}], ie an aray of json object

User avatar
Irrlicht
Dragon
Posts: 426
Joined: Mon Feb 09, 2009 10:53 am

Re: Sorting json object by values

Post by Irrlicht »

aliasmask wrote:
Fri May 11, 2018 7:34 pm
Yep, that's the way I wrote that so I can have my keys in alphabetical order. If you want to sort the object by value and reorder the keys then you can create an array of objects and use the normal json.sort on it then rebuild the object.

Code: Select all

[H: myObj = '{"12":5,"8":9,"21":3}']
[H: myArray = "[]"]
[H, foreach(key,myObj): myArray = json.append(myArray,json.set("{}","key",key,"value",json.get(myObj,key)))]
[H: myArray = json.sort(myArray,"d","value")]
[H: newObj = "{}"]
[H, foreach(obj,myArray): newObj = json.set(newObj,json.get(obj,"key"),json.get(obj,"value"))]
[dialog("D"):{<pre>[R: json.indent(replace(newObj,"<","&lt;"))]</pre>}]
output:

Code: Select all

{
    "8": 9,
    "12": 5,
    "21": 3
}
IMO, the above is shorthand for what the values really mean. ie the key represents something as does the value and should actually be in an array of objects instead of a single object. For example: [{"carNumber":8,"initiative":9},{"carNumber":12,"initiative":5}] I don't know what it actually means, but I think it's something similar.
Thanks, helpful as usual.
"There are many ways my Son, to find where the souls of Demons remain...
But it takes only one second of despair and of doubt until, at last, your Soul they will gain..."

Post Reply

Return to “Macros”