Search code examples
javajsonspringjettison

compare org.codehaus.jettison.json.JSONArray without regard to order


I've got 2 JSONArray full of integers.

I want to compare them for equal content without regard for order.

So:

[1, 2] == [1, 2] TRUE [1, 2] == [2, 1] TRUE

JSONArray has

public boolean equals(Object o) 

but it returns FALSE for [1, 2] == [2, 1]

So, I rolled my own:

public boolean isEqual(JSONArray inputJsonArray, 
                       JSONArray outputJsonArray) throws JSONException{
    boolean equal=true, done;
    int idx = 0;      

    if (inputJsonArray.length() == outputJsonArray.length()){

        //make sure all elements in input array are in output array
        done=false;
        while (!done){
            if(idx >= inputJsonArray.length()){
               done=true;
            }
            else if (isIntInJsonArray(outputJsonArray,
                                      inputJsonArray.getInt(idx)) == false){
                     equal = false;
                     done=true;
            }
            else{
                     idx ++;
            }

        }

        if (equal){

            //make sure all elements in output array are in input array
            done=false;
            while (!done){
                  if (idx >= outputJsonArray.length()){
                       done=true;
                  }
                  else if (isIntInJsonArray(inputJsonArray,
                                         outputJsonArray.getInt(idx)) == false){

                            equal = false;
                            done=true;
                  }
                  else{
                            idx++;
                  }

            }          
        }           
    }
    else{
            equal = false;
    }

    return equal;

}

Basically, I check if both JSONArrays are the same length. If they are then I make sure every element in the outputJsonArray is in the inputJsonArray and vice versa. The workhorse method that does this is:

private boolean isIntInJsonArray(JSONArray inputJsonArray, int mInt) throws JSONException{
    boolean found=false, done=false;
    int idx = 0;

    while (!done){
            if(idx >= inputJsonArray.length()){
               done=true;
            }
            else if (inputJsonArray.getInt(idx) == mInt){
               found = true;
               done=true;
            }
            else{
               idx ++;
            }              
    }

    return(found);
 }   

This strikes me like an awful lot of code. Does anyone know if there is a simpler way to do this?


Solution

  • Convert the arrays to JSONObject then use its equals method.

    JSONArray arr1 = new JSONArray();
    JSONArray arr2 = new JSONArray();
    
    arr1.put(1);
    arr1.put(2);
    arr1.put(3);
    arr1.put(4);
    arr1.put(5);
    
    arr2.put(2);
    arr2.put(1);
    arr2.put(3);
    arr2.put(5);
    arr2.put(4);
    
    JSONObject o1 = arr1.toJSONObject(arr1);
    JSONObject o2 = arr2.toJSONObject(arr2);
    
    System.out.println(o1.equals(o2)); //true
    

    Looking at the source code of JSONObject, it is using its underlying map to check equality.

    @Override
    public boolean equals(Object obj) {
       if (obj instanceof JSONObject) {
          return myHashMap.equals(((JSONObject)obj).myHashMap);
       } else {
          return false;
       }
    }
    

    The equals implementation of underlying map is disregarding the order of its content

    public boolean equals(Object o) {
        if (o == this)
            return true;
    
        if (!(o instanceof Map))
            return false;
        Map<K,V> m = (Map<K,V>) o;
        if (m.size() != size())
            return false;
    
        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
    
        return true;
    }