Home > Net >  find differences between lists of objects
find differences between lists of objects

Time:01-07

In Java 11 , is there an elegant way to find the differences between 2 lists of objects? Filtering should be done on one 'value' property of a simple col1, value object. Normally the object will contain at least 2 other properties.

Suppose I have these 2 lists:

  • List 1: ( { "left","one" }, { "left","two" } )
  • List 2: ( { "right","two" }, { "right","three" } )

The result should be a list with:

  • ( { "left","one" }, { "right","three" } )

Of course there is a simplistic old way of doing this. That simple program gives:

ColValueObject{base='left', value='Value one'} ColValueObject{base='right', value='Value four'}

public class CompareListOfObjects {
  public static void main(String[] args) {
    List<ColValueObject> list1 = List.of(
            new ColValueObject("left", "Value one"),
            new ColValueObject("left", "Value two"),
            new ColValueObject("left", "Value three"));
    List<ColValueObject> list2 = List.of(
            new ColValueObject("right", "Value two"),
            new ColValueObject("right", "Value three"),
            new ColValueObject("right", "Value four"));

    List<ColValueObject> result = findDifferencesBetweenLists(list1, list2);
    result.forEach(System.out::println);
  }

  private static List<ColValueObject> findDifferencesBetweenLists(List<ColValueObject> list1, List<ColValueObject> list2) {
    List<ColValueObject> result = new ArrayList<>();
    findUniqueEntriesInList((List<ColValueObject>) list1, (List<ColValueObject>) list2, (List<ColValueObject>) result);
    findUniqueEntriesInList((List<ColValueObject>) list2, (List<ColValueObject>) list1, (List<ColValueObject>) result);
    return result;
  }

  private static void findUniqueEntriesInList(List<ColValueObject> list1, List<ColValueObject> list2, List<ColValueObject> result) {
    for (ColValueObject l1 : list1) {
      boolean found = false;
      for (ColValueObject l2 : list2) {
        if (l1.getValue().equals(l2.getValue())) {
          found = true;
          break;
        }
      }
      if (!found) {
        result.add(l1);
      }
    }
  }
}

class ColValueObject {
  private String base;
  private String value;

  public ColValueObject(String base, String value) {
    this.base = base;
    this.value = value;
  }

  public String getBase() {
    return base;
  }

  public void setBase(String base) {
    this.base = base;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

  @Override
  public String toString() {
    return "ColValueObject{"  
            "base='"   base   '\''  
            ", value='"   value   '\''  
            '}';
  }
}

CodePudding user response:

You could override the equals method of your ColValueObject type so you can match these objects only by value.

And then I recommend using the removeAll method which is either in any collection implementing Collection (Java Doc) or in the CollectionUtils library.

Basically you would have two resulting lists:

List<ColValueObject> result1 = CollectionUtils.removeAll(list2, list1);
List<ColValueObject> result2 = CollectionUtils.removeAll(list1, list2);

Finally you can use the addAll method to get the final result list.

CodePudding user response:

You can first group your list by the rate of each object and count the number of occurences and second filter the resulting stream if the occurences equals 1. Afterwards you have to map the first object of EntrySet to ColValueObject and collect the final list.

List<ColValueObject> result = Stream.of(list1, 
list2).flatMap(List::stream).collect(groupingBy(d -> d.getValue())).entrySet().stream().filter(e -> e.getValue().size() == 1).map(e -> e.getValue().get(0)).collect(Collectors.toList());
    System.out.println(result);

To use this, the following static import ist necessary:

import static java.util.stream.Collectors.groupingBy;

CodePudding user response:

Looks like this is pretty simple algorithm. All you need is group all objects by the value (i.e. create a Map) and retreive only these objects, that are single for the given key.

public static List<ColValueObject> getUnique(List<ColValueObject> one,
                                             List<ColValueObject> two) {
    // group by value
    Map<String, List<ColValueObject>> map =
            Stream.of(one, two)
                  .flatMap(List::stream)
                  .collect(Collectors.groupingBy(ColValueObject::getValue));
    
    // retreive unique lements only
    return map.values().stream()
              .filter(objs -> objs.size() == 1)
              .map(objs -> objs.get(0))
              .collect(Collectors.toList());
}
  •  Tags:  
  • java
  • Related