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:
If you are going to display the data contained in the JSONArray
then it may make sense to sort it in the adapter itself. For example, the ArrayAdapter<T>
class already has the requisite methods such as Insert
, Remove
, and of course Sort
.
adapter.sort(new Comparator<JSONObject>(){
@Override
public int compare(JSONObject arg0, JSONObject arg1) {
return arg0.optString("SortField", "").compareTo(arg1.optString("SortField","")) ;
}
});
//My script
//HEADER add final variables
private final int TYPE_STRING = 1;
private final int TYPE_INT = 2;
private final int TYPE_DUBLE = 3;
//METHOD GET SORT JSONARRAY
public JSONArray getSortJSONArray()
{
JSONArray json = new JSONArray ([{"carid":"957502","vin":"XXXXX","carbrand":"CADILLAC","carmodel":"CTS","carname":"CADILLAC CTS седан CTS PERFORMANC 2.0L AWD AK4 2 4WD AT-6 276 (Л.С.)","carmodificationname":" седан CTS PERFORMANC 2.0L AWD AK4 2 4WD AT-6 276 (Л.С.)","carcolorname":"Opulent Blue Metallic - ярко-синий металлик","price":"3410000","rgb":"","volumereal":"2,00","power":"276"},{"carid":"957502","vin":"XXXXX","carbrand":"CADILLAC","carmodel":"CTS","carname":"CADILLAC CTS седан CTS PERFORMANC 2.0L AWD AK4 2 4WD AT-6 276 (Л.С.)","carmodificationname":" седан CTS PERFORMANC 2.0L AWD AK4 2 4WD AT-6 276 (Л.С.)","carcolorname":"Opulent Blue Metallic - ярко-синий металлик","price":"3460000","rgb":"","volumereal":"1,00","power":"272"}]");
/*halper - My halper */
JSONArray sorJsonArray = halper.sort(json, getComparator("power",TYPE_INT));
return sorJsonArray;
}
private Comparator getComparator(final String tagJSON,final int type)
{
Comparator c = new Comparator()
{
public int compare(Object a, Object b)
{
try
{
JSONObject ja = (JSONObject)a;
JSONObject jb = (JSONObject)b;
switch (type)
{
case TYPE_STRING:// String
return ja.optString(tagJSON, "")
.toLowerCase()
.compareTo(jb.optString(tagJSON, "").toLowerCase());
case TYPE_INT:// int
int valA = ja.getInt(tagJSON);
int valB = jb.getInt(tagJSON);
if(valA > valB)
return 1;
if(valA < valB)
return -1;
case TYPE_DUBLE:// double
String v1 = ja.getString(tagJSON).replace(",",".");
String v2 = jb.getString(tagJSON).replace(",",".");
double valAd = new Double(v1);// ja.getDouble(tagJSON);
double valBd = new Double(v2);// jb.getDouble(tagJSON);
if(valAd > valBd)
return 1;
if(valAd < valBd)
return -1;
}
}
catch (Exception e)
{
e.printStackTrace();
}
return 0;
}
};
return c;
}
//My Halper class
public class Halpe {
public void Halpe(){}
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;
}}
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;
}
One example with Date
field:
public class JsonObjectComparator implements Comparator<JSONObject> {
private final String fieldName;
private Class<? extends Comparable> fieldType;
public JsonObjectComparator(String fieldName, Class<? extends Comparable> fieldType) {
this.fieldName = fieldName;
this.fieldType = fieldType;
}
@Override
public int compare(JSONObject a, JSONObject b) {
String valA, valB;
Comparable newInstance_valA, newInstance_valB;
int comp = 0;
try {
Constructor<? extends Comparable> constructor = fieldType.getConstructor(String.class);
valA = a.getString(fieldName);
valB = b.getString(fieldName);
if (fieldType.equals(Date.class)) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
newInstance_valA = dateFormat.parse(valA);
newInstance_valB = dateFormat.parse(valB);
} else {
newInstance_valA = constructor.newInstance(valA);
newInstance_valB = constructor.newInstance(valB);
}
comp = newInstance_valA.compareTo(newInstance_valB);
} catch (Exception e) {
System.out.println(e.getMessage());
}
if(comp > 0)
return 1;
if(comp < 0)
return -1;
return 0;
}
}
public static void main(String[] args) throws JSONException {
JSONObject o1 = new JSONObject();
o1.put("key1", "26-06-2014");
JSONObject o2 = new JSONObject();
o2.put("key1", "30-11-2011");
JSONObject o3 = new JSONObject();
o3.put("key1", "15-07-2014");
JsonObjectComparator comparator = new JsonObjectComparator("key1", Date.class);
List<JSONObject> l = new ArrayList<>();
l.add(o1);
l.add(o2);
l.add(o3);
Collections.sort(l, comparator);
}
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
Just to be clear the code above for the sort comparator is not correct. You can't compare string like you have above as you could in a language like Ruby. This could be written much more succinctly as follows. Otherwise the logic is sound.
Collections.sort( jsonValues, new Comparator<JSONObject>() {
@Override
public int compare(JSONObject a, JSONObject b) {
String valA = new String();
String valB = new String();
try {
valA = (String) a.get("keyOfValueToSortBy");
valB = (String) b.get("keyOfValueToSortBy");
}
catch (JSONException e) {
Log.e(LOG_TAG, "JSONException in combineJSONArrays sort section", e);
}
return valA.compareTo(valB);
}
});