Android如何对JSONArray中的JSONObjects进行排序

26
我已经创建了一个json对象的json数组。现在我需要根据json对象中的某个值对JSONArray进行排序。以前,我会这样对自定义对象的ArrayList进行排序:
比较器:
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);
    }
}

然后对ArrayList进行排序:

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

或者:

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

但是,当我尝试像这样使用JSONArray(JA =我的jsonarray)时:

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

Collections.sort出现错误:

Collections中的sort(List, Comparator)方法对于参数(JSONArray, ThisActicity.KreeftenComparatorNL)不适用。

请问有谁知道如何对JSONArray进行排序吗?


可能是 http://stackoverflow.com/questions/4833084/is-there-any-easy-way-to-sort-a-jsonarray-of-objects-by-an-attribute-in-android?rq=1 的重复问题。 - petey
考虑一下:如果您可以在构建JsonArray之前进行排序,请这样做。您也可以稍后在JavaScript中对其进行排序。我认为从JsonArray构建列表,对列表进行排序,然后重新构建JsonArray非常糟糕 :) - Christophe Roussy
6个回答

41

问题在于JSONArray更多地包含了JSON对象(和其他的JSON数组),这些最终都是字符串。将这些字符串完全反序列化成POJO,然后排序,再转换回JSON格式会比较繁重。

其次,一个JSONArray可以包含:布尔值、JSONArray、JSONObject、数字、字符串或JSONObject.Null对象。也就是说,它是混合类型的,很难将元素仅仅倒入某种类型的列表中进行排序,然后通过列表传递排好序的元素再次放回JSON数组。从JSONArray获取每个元素的公共类型的唯一确定方法是使用Object get()方法。当然,那时你只有Object对象,无法对它们进行任何有意义的排序,除非重新考虑序列化问题。

假设你的JSONArray包含具有同构结构的值,你可以遍历JSONArray,在每个元素上调用其中一种类型的get()方法,将它们倒入List类型中,然后在该列表上进行排序。如果你的JSONArray仅包含像字符串或数字这样的“简单”类型,那么这就比较容易。下面不是确切的代码,但类似于:

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);

当然,如果你有嵌套的对象,这可能会变得有点棘手。如果你想排序的值存储在顶层,则情况可能不会那么糟糕...

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

然后使用这样的比较器进行排序:

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;    
    }
}

再次说明,这对您的JSONArray数据的同质性做出了一些假设。如有可能,请根据自己的情况进行调整。另外,您还需要添加异常处理等内容。祝您编码愉快!

编辑 根据评论进行修正


2
这个例子很接近,但是它不能编译。由于Java没有运算符重载,所以你不能这样比较字符串。这个例子应该返回valA.compareTo(valB)。 - SoWeLie
但我想一个普通的Java开发人员可以做到,不需要谷歌或这个。 - subash
其实,我在想如果我们需要对JSonArrays进行排序以便比较,那么应该有一种有效的方法使用它们的哈希值...虽然我没有尝试过,但对于人类来说,结果顺序看起来会是随机的。 - ntg

10

为了填充Android列表ArrayAdapter,我只需要这样做。以下是我的操作:

从JSONArray构建列表的Activity代码:

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);

而在JSONUtil中(我的辅助程序):

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;
}

也许可以在适配器本身中执行此操作:https://dev59.com/wWcs5IYBdhLWcg3wYy5T#32213875 - Hugh Jeffner

7

为了明确起见,上述排序比较器的代码是不正确的。你不能像在Ruby这样的语言中那样比较字符串。否则,逻辑是正确的,可以改写得更简洁。

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);
    }
});

1
你能不能直接返回 valA.compareTo(valB)? - SoWeLie

1
//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;
    }

//我的辅助类

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;
    }}

1
如果您要显示JSONArray中包含的数据,那么在适配器本身中对其进行排序可能是有意义的。例如,ArrayAdapter<T>类已经具备了必要的方法,如InsertRemoveSort
adapter.sort(new Comparator<JSONObject>(){

    @Override
    public int compare(JSONObject arg0, JSONObject arg1) {

        return arg0.optString("SortField", "").compareTo(arg1.optString("SortField","")) ;

    }

});

1
一个带有Date字段的例子:
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);
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接