简体   繁体   中英

Java - best way to compare two List<List<String>>?

What's the best way to compare the String elements of two List<List<String>> ...

At the end, I want to know if they contain the same elements (true) or not (false)

This two lists I want to compare:

ObservableList<List<String>> fnlData = FXCollections.observableList(new LinkedList<>());;

List<List<String>> fnlDataTMP = new LinkedList<>();

I searched for already answered questions in the forum, but nothing helped me ..

Try fnlData.equals(fnlDataTMP) if both list are in order

or if order does not matter, try creating hash set and then compare using equals

new HashSet(fnlData).equals(new HashSet(fnlDataTMP))

looks like you need a double iteration

boolean checkEqual(List<List<String>> l1,List<List<String>> l2){
  if(l1.size() != l2.size()){
    return false;
  }
  if(l1.hashCode() != l2.hashCode()){
    return false;
  }
  for(int i=0; i<l1.size(); i++) {
    List<String> curr = l1.get(i);
    List<String> comp = l2.get(i);
    if(curr.size() != comp.size()){
      return false;
    }
    if(curr.hashCode() != comp.hashCode()){
      return false;
    }
    for(int j=0; j<curr.size(); j++) {
      if(!curr.get(j).equals(comp.get(j))){
        return false;
      }
    }
  }
  return true;
}

You can improve the solution checking first difference of hashCode

if(l1.hashCode() != l2.hashCode()){
  return false;
}

if hashCode are equal, then check eventually deep difference

I don't think there is a way that let's you achieve that out of the box.

You can do something like the functional java List.join method to quickly generate 2 Lists and compare these:

List<String> joinedFnlData = jf.data.List.join(fnlData);
List<String> joinedFnlDataTMP = jf.data.List.join(fnlDataTMP);

CollectionUtils.isEqualCollection(joinedFnlData, joinedFnlDataTMP);

Things to note:

  • This is probably not the cheapest operation - so it should not be invoked too often in a time critical scenario (eg UI thread)
  • It does not do a "real" equals - for that you would have to do a nested loop like in the above answer. This checks that both joined lists have the same elements with the same cardinality: eg if fnlData has 2 lists with "1" and "2" as the only elements and fnlDataTMP has 1 list with "1", "2" as the elements, this would mark both as equal. Depending on your scenario this might be irrelevant - if this is relevant I don't see a way around nested loops.

If by same elements you mean that the two lists are exacly the same but in a different order, then i suggest you sort the to lists and then compare them.

boolean isEqual(List<String> list1, List<String> list2) {
        if (list1.size() != list2.size()) return false;
        Collections.sort(list1);
        Collections.sort(list2);
        int i = 0;
        for (String element : list1) {
            if (!element.equals(list2.get(i))) return false;
            i++;
         }
        return true;
    }

I didn't test it yet!

For a Collections (Lists) to be equal, both need to be a proper subset of each other. Thus list1.containsAll(list2) and list2.containsAll(list1) . For a List within a List, you will have to loop, but that's essentially what any built-in library has to do anyway.

I came up with a solution that doesn't need to have two inner loops by using Collections.sort(List list) , which sorts a List in place, and List.containsAll(java.util.Collection) , which compares two Lists for their elements.

Sample Code:

    //Creating two lists for comparison and their inner lists
    List<List<String>> list1 = new LinkedList<>();
    List<List<String>> list2 = new LinkedList<>();

    LinkedList<String> l11 = new LinkedList<>();
    l11.add("a");
    l11.add("b");
    l11.add("c");

    LinkedList<String> l12 = new LinkedList<>();
    l12.add("d");
    l12.add("e");
    l12.add("f");

    LinkedList<String> l21 = new LinkedList<>();
    l21.add("b");
    l21.add("c");
    l21.add(new String("a"));

    LinkedList<String> l22 = new LinkedList<>();
    l22.add("d");
    l22.add("e");
    l22.add("f");

    list1.add(l11);
    list1.add(l12);
    list2.add(l22);
    list2.add(l21);

    for (List<String> list : list1){
        Collections.sort(list);
    }

    for (List<String> list : list2){
        Collections.sort(list);
    }

    System.out.println(list1.containsAll(list2) && list2.containsAll(list1)); //prints true

If you don't want to change the order of the elements in the inner Lists you can create copies of the outer Lists and perform the operations on them.

Note: This only works for sortable collections.

Store one of the list in a HashMap and then iterate through the other list and check if the Map already contains that KEY. Ofcourse you have to ensure that KEY types match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM