Question

anybody know an efficient way to decide if two arraylists contain the same values?

Code:

ArrayList<String> dummy1= new ArrayList<String>();
list1.put("foo");
list1.put("baa");

ArrayList<String> dummy2= new ArrayList<String>();
list1.put("baa");
list1.put("foo");

dummy1 == dummy2

the challenge is that the arraylists has not the same value order..

(foo, baa) == (foo, baa) // per definition :)

i need to get this

(foo, baa) == (baa, foo) // true

so what would be your approach?

Was it helpful?

Solution

Just sort it first.

public  boolean equalLists(List<String> one, List<String> two){     
    if (one == null && two == null){
        return true;
    }

    if((one == null && two != null) 
      || one != null && two == null
      || one.size() != two.size()){
        return false;
    }

    //to avoid messing the order of the lists we will use a copy
    //as noted in comments by A. R. S.
    one = new ArrayList<String>(one); 
    two = new ArrayList<String>(two);   

    Collections.sort(one);
    Collections.sort(two);      
    return one.equals(two);
}

Honestly, you should check your data structure decision. This seems more like a set problem. Sorting then comparing will take O(nlog n) while a HashSet comparison will only be O(n).

OTHER TIPS

The sort method runs in O(n log n) but we can do better. First perform null and size comparisons. Then use a HashMap<String, Integer> and store the frequency of a particular string as the value. Do this for one of the lists, then iterate through the other and check that the map contains the string and has the same frequency. This method is O(n).

Assuming that the lists contain no duplicates, you can use two temporary HashSet<String> objects for that.

Construct sets of Strings from both ArrayList<String>s that you are comparing, and then check that the first set has all items from the second list, and also the second set contains all items from the first list.

You can do it like this:

List<String> a = ...;
List<String> b = ...;
Set<String> setA = new HashSet<String>(a);
Set<String> setB = new HashSet<String>(b);
boolean same = setA.containsAll(b) && setB.containsAll(a);

If you must account for duplicates, replace HashSet<String> with HashMap<String,Integer> to make and compare the corresponding frequency counters.

You should sort the two ArrayLists, then do an equal comparison. However, you may need to remove duplicates (I'm not sure about your policy on duplicates).

The most efficient way depends on the size of the array.

  • For very small lists, using contains() is probably most efficient. (Maybe for lists with between 0 to 5 elements ... I'd guess.)

  • For medium to large sized lists you can either:

    • sort the both array lists and compare them pair-wise,

    • sort one list and use binary search to probe the values in the second one.

    • convert one to a HashSet and probe with the values in the second one.

The complexity analysis is not straight-forward as it depends on the likelihood that the lists are equal ... or not. The "worst case" is when the lists are equal, because that means that you have to check all elements before you can return true. In that case the complexities are O(N^2), O(NlogN), O(NlogN) and O(N) respectively.

That doesn't take into account space usage, and (in Java) the performance impact of using a lot of memory,

There is also the issue of the "constants of proportionality"; e.g. O(NlogN) can be faster than O(N) for small values of N.

In short ... there is no single solution that is always going to be best.

Here you have a Java 8, please specify if you need a Java 7 solution.

Assumption 1: The ArrayLists are not nulls.

Its time complexity is O(N), where N is the size of any of the inputs.

Its memory complexity in addition to the input is 0(N)

In other words, its time and memory complexity are linear.

Theoretically you could have a constant O(1)memory complexity, but it would involve removing elements from the a1 while adding them to the setA1. In my opinion, this relies too much on garbage collector so hopefully this solution will be enough for you.

import java.util.*;

public class ArraySameValuesSolver {

    public boolean of(List<String> list1, List<String> list2) {
        if (list1.size() != list2.size())
            return false;
        Map<String, Integer> occ = new HashMap<>();
        list1.stream().forEach(s -> incrementOccurences(occ, s));
        for (String s: list2) {
            decrementOccurrences(occ, s);
            if (occ.get(s) < 0)
                return false;
        }
        return true;
    }

    private void incrementOccurences(Map<String, Integer> occ, String s) {
        if (!occ.containsKey(s))
            occ.put(s, 1);
        else
            occ.put(s, occ.get(s) + 1);
    }

    private void decrementOccurrences(Map<String, Integer> occ, String s) {
        if (!occ.containsKey(s))
            occ.put(s, -1);
        else
            occ.put(s, occ.get(s) - 1);
    }

}
  public boolean isListEquals( List listA , List listB ) {
    boolean result = false;

    if ( ( listA == listB ) ) {
      result = true;
      return result;
    }

    if ( ( listA == null ) || ( listB == null ) ) {
      return result;
    }

    if ( listA.size() != listB.size() ) {
      return result;
    }

    List listC = new ArrayList( listA );
    listC.removeAll( listB );
    if ( listC.size() > 0 ) {
      return result;
    }

    result = true;
    return result;
  }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top