Android how to sort JSONArray of JSONObjects

I have made a jsonarray of jsonobjects. Now I need to sort the JSONArray on base of a value from the jsonobjects. Formerly I sorted ArrayLists of custom objects like this:

Comparators:

public class KreeftenComparatorLA implements Comparator<Kreeft> {
    public int compare(Kreeft left, Kreeft right) {
        return left.latijnseNaam.compareTo(right.latijnseNaam);
    }
}
public class KreeftenComparatorNL implements Comparator<Kreeft> {
    public int compare(Kreeft left, Kreeft right) {
        return left.naam.compareTo(right.naam);
    }
}

And then sort the arraylist:

Collections.sort(db.lijst, new KreeftenComparatorLA());

or:

Collections.sort(db.lijst, new KreeftenComparatorNL());

But when I try the same thing with the JSONArray like this (JA = my jsonarray)

Collections.sort(JA, new KreeftenComparatorNL());

the Collections.sort gives an error:

The method sort(List, Comparator) in the type Collections is not applicable for the arguments (JSONArray, ThisActicity.KreeftenComparatorNL)

Does anybody know how to sort the JSONArray?


Solution 1:

The issue is that JSONArray more or less holds JSONObjects (and other JSONArrays) which ultimately are strings. Deserializing the strings entirely into POJOs, sorting those, then back into JSON is fairly heavy.

The second issue is that a JSONArray can contain: Boolean, JSONArray, JSONObject, Number, String, or the JSONObject.NULL object; i.e. it is mixed types, making it hard to just dump the elements into a List of some type and sort that, then pass through the list dumping sorted items back into the JSON array. the only certain way to get a common type of each element from the JSONArray is using the Object get() method.. of course then all you have is Object objects and won't be able to do any meaningful sorting on them without revisiting the serialization issue.

Assuming your JSONArray contains homogeneously structured values, you could iterate through the JSONArray, calling one of the typed get() methods on each one, dumping them into a List type, then sorting on that. If your JSONArray just holds "simple" type like String or numbers, this is relatively easy. This isn't exact code but something like:

List<String> jsonValues = new ArrayList<String>();
for (int i = 0; i < myJsonArray.length(); i++)
   jsonValues.add(myJsonArray.getString(i));
Collections.sort(jsonValues);
JSONArray sortedJsonArray = new JSONArray(jsonValues);

Of course, if you have nested objects this can get a little trickier. If the value(s) you want to sort on live in the top level, it may not be soo bad...

List<JSONObject> jsonValues = new ArrayList<JSONObject>();
for (int i = 0; i < myJsonArray.length(); i++)
   jsonValues.add(myJsonArray.getJSONObject(i));

Then use a comparator like this to sort:

class JSONComparator implements Comparator<JSONObject>
{

    public int compare(JSONObject a, JSONObject b)
    {
        //valA and valB could be any simple type, such as number, string, whatever
        String valA = a.get("keyOfValueToSortBy");
        String valB = b.get("keyOfValueToSortBy");

        return valA.compareTo(valB);
        //if your value is numeric:
        //if(valA > valB)
        //    return 1;
        //if(valA < valB)
        //    return -1;
        //return 0;    
    }
}

Again, this makes some assumptions about the homogeneity of the data in your JSONArray. Adjust to your case if possible. Also you will need to add your exception handling, etc. Happy coding!

edit fixed based on comments

Solution 2:

In order to fill up an Android list ArrayAdapter I needed to do just this. This is how I did it:

Activity code building a list from a JSONArray:

JSONArray kids = node.getJSONArray("contents");
kids = JSONUtil.sort(kids, new Comparator(){
   public int compare(Object a, Object b){
      JSONObject    ja = (JSONObject)a;
      JSONObject    jb = (JSONObject)b;
      return ja.optString("name", "").toLowerCase().compareTo(jb.optString("name", "").toLowerCase();
   }
});
// in my case I wanted the original larger object contents sorted...
node.put("contents", kids);

And in JSONUtil (my helper):

public static JSONArray sort(JSONArray array, Comparator c){
    List    asList = new ArrayList(array.length());
    for (int i=0; i<array.length(); i++){
      asList.add(array.opt(i));
    }
    Collections.sort(asList, c);
    JSONArray  res = new JSONArray();
    for (Object o : asList){
      res.put(o);
    }
    return res;
}