I have an object that has a list as its property, e.g.
public class A {
private String aName;
private List<B> bList;
}
public class B {
private String bName;
}
Lets assume that we have two lists of A
's:
List<A> existingList = new ArrayList<A>();
// populate it with a list of A's which in turn, each has its own list of B's
List<A> newList = new ArrayList<A>();
// populate it with possibly some new A's and/or, an existing A which its property B has new items
With that in mind, I would like to know the fastest way to compare these two list of A
's, and add the delta of these two lists to the existingList
.
Note that we are also comparing a list of B
's for A
's in both lists, so if there is a matching A
's, but there is a delta of their B
's, we should be able to add it to existingList
's A
's bList
.
Equally, if we detect an item has been deleted from newList
, we should remove that from existingList
.
Note, this is not simply about comparing two objects, but rather finding the delta deep in the object graph and updating or adding new and/or existing parts. Here is the sample example:
package collection.delta.model;
import java.util.List;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
package collection.delta.model;
import java.util.List;
import java.util.Objects;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
public class A {
private String aName;
private List<B> bList;
public String getaName() {
return aName;
}
public void setaName(String aName) {
this.aName = aName;
}
public List<B> getbList() {
return bList;
}
public void setbList(List<B> bList) {
this.bList = bList;
}
public A(String name, List<B> bList) {
this.aName = name;
this.bList = bList;
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o == this) {
return true;
}
if (!(o instanceof A)) {
return false;
}
A b = (A) o;
return StringUtils.isNotBlank(aName) && StringUtils.equalsAnyIgnoreCase(b.getaName(), aName)
&& CollectionUtils.disjunction(this.getbList(), b.getbList()).isEmpty();
}
@Override
public int hashCode() {
if (StringUtils.isBlank(aName)) {
return 31;
}
return Objects.hashCode(aName);
}
package collection.delta.model;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
public class B {
private String bName;
public String getbName() {
return bName;
}
public void setbName(String bName) {
this.bName = bName;
}
public B(String name) {
this.bName = name;
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o == this) {
return true;
}
if (!(o instanceof B)) {
return false;
}
B b = (B) o;
return StringUtils.isNotBlank(bName) && StringUtils.equalsAnyIgnoreCase(b.getbName(), bName);
}
@Override
public int hashCode() {
if (StringUtils.isBlank(bName)) {
return 31;
}
return Objects.hashCode(bName);
}
}
package collection.delta;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import collection.delta.model.A;
import collection.delta.model.B;
public class App {
public static void main( String[] args ) {
List<A> originalA = new ArrayList<A>();
List<A> newA = new ArrayList<A>();
List<B> bListOriginalA1 = new ArrayList<B>();
bListOriginalA1.add(new B("originalA1_B1"));
bListOriginalA1.add(new B("originalA1_B2"));
bListOriginalA1.add(new B("originalA1_B3"));
bListOriginalA1.add(new B("originalA1_B4"));
A originalA1 = new A("originalA1", bListOriginalA1);
List<B> bListOriginalA2 = new ArrayList<B>();
bListOriginalA2.add(new B("originalA2_B1"));
bListOriginalA2.add(new B("originalA2_B2"));
bListOriginalA2.add(new B("originalA2_B3"));
bListOriginalA2.add(new B("originalA2_B4"));
A originalA2 = new A("originalA2", bListOriginalA2);
List<B> bListOriginalA3 = new ArrayList<B>();
bListOriginalA3.add(new B("originalA3_B1"));
bListOriginalA3.add(new B("originalA3_B2"));
bListOriginalA3.add(new B("originalA3_B3"));
bListOriginalA3.add(new B("originalA3_B4"));
A originalA3 = new A("originalA3", bListOriginalA3);
originalA.add(originalA1);
originalA.add(originalA2);
originalA.add(originalA3);
List<B> bListNewA1 = new ArrayList<B>();
bListNewA1.add(new B("originalA1_B1"));
bListNewA1.add(new B("originalA1_B2"));
bListNewA1.add(new B("originalA1_B3"));
bListNewA1.add(new B("originalA1_B4"));
A newA1 = new A("originalA1", bListNewA1);
List<B> bListNewA2 = new ArrayList<B>();
bListNewA2.add(new B("originalA2_B1"));
bListNewA2.add(new B("originalA2_B2"));
bListNewA2.add(new B("originalA2_B3"));
bListNewA2.add(new B("originalA2_B4"));
A newA2 = new A("originalA2", bListNewA2);
List<B> bListNewA3 = new ArrayList<B>();
bListNewA3.add(new B("originalA3_B1"));
bListNewA3.add(new B("originalA3_B2"));
bListNewA3.add(new B("originalA3_B5"));
bListNewA3.add(new B("originalA3_B4"));
A newA3 = new A("originalA3", bListNewA3);
List<B> bListNewA4 = new ArrayList<B>();
bListNewA4.add(new B("A4_B1"));
bListNewA4.add(new B("A4_B2"));
bListNewA4.add(new B("A4_B3"));
bListNewA4.add(new B("A4_B4"));
A newA4 = new A("originalA4", bListNewA4);
newA.add(newA1);
newA.add(newA2);
newA.add(newA3);
newA.add(newA4);
List<A> result = CollectionUtils.disjunction(originalA, newA).stream().collect(Collectors.toList());
for (A a : newA) {
for (A aResult : result) {
if (StringUtils.equalsAnyIgnoreCase(a.getaName(), aResult.getaName())) {
originalA.add(aResult);
}
}
}
System.out.println("");
}
}
This works:
package collection.delta;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import collection.delta.model.A;
import collection.delta.model.B;
public class App {
public static void main( String[] args ) {
List<A> originalA = new ArrayList<A>();
List<A> newA = new ArrayList<A>();
List<B> bListOriginalA1 = new ArrayList<B>();
bListOriginalA1.add(new B("originalA1_B1"));
bListOriginalA1.add(new B("originalA1_B2"));
bListOriginalA1.add(new B("originalA1_B3"));
bListOriginalA1.add(new B("originalA1_B4"));
A originalA1 = new A("originalA1", bListOriginalA1);
List<B> bListOriginalA2 = new ArrayList<B>();
bListOriginalA2.add(new B("originalA2_B1"));
bListOriginalA2.add(new B("originalA2_B2"));
bListOriginalA2.add(new B("originalA2_B3"));
bListOriginalA2.add(new B("originalA2_B4"));
A originalA2 = new A("originalA2", bListOriginalA2);
List<B> bListOriginalA3 = new ArrayList<B>();
bListOriginalA3.add(new B("originalA3_B1"));
bListOriginalA3.add(new B("originalA3_B2"));
bListOriginalA3.add(new B("originalA3_B3"));
bListOriginalA3.add(new B("originalA3_B4"));
A originalA3 = new A("originalA3", bListOriginalA3);
originalA.add(originalA1);
originalA.add(originalA2);
originalA.add(originalA3);
List<B> bListNewA1 = new ArrayList<B>();
bListNewA1.add(new B("originalA1_B1"));
bListNewA1.add(new B("originalA1_B2"));
bListNewA1.add(new B("originalA1_B3"));
bListNewA1.add(new B("originalA1_B4"));
A newA1 = new A("originalA1", bListNewA1);
List<B> bListNewA2 = new ArrayList<B>();
bListNewA2.add(new B("originalA2_B1"));
bListNewA2.add(new B("originalA2_B3"));
bListNewA2.add(new B("originalA2_B4"));
bListNewA2.add(new B("originalA2_B2"));
A newA2 = new A("originalA2", bListNewA2);
List<B> bListNewA3 = new ArrayList<B>();
bListNewA3.add(new B("originalA3_B1"));
bListNewA3.add(new B("originalA3_B2"));
bListNewA3.add(new B("originalA3_B5"));
bListNewA3.add(new B("originalA3_B4"));
A newA3 = new A("originalA3", bListNewA3);
List<B> bListNewA4 = new ArrayList<B>();
bListNewA4.add(new B("A4_B1"));
bListNewA4.add(new B("A4_B2"));
bListNewA4.add(new B("A4_B3"));
bListNewA4.add(new B("A4_B4"));
A newA4 = new A("originalA4", bListNewA4);
newA.add(newA1);
newA.add(newA2);
newA.add(newA3);
newA.add(newA4);
List<A> result = newA.stream()
.filter(not(new HashSet<A>(originalA)::contains))
.collect(Collectors.toList());
A tempA = null;
B tempB = null;
List<B> bList = null;
for (A a : result) {
if (!containsName(originalA, a.getaName())) {
originalA.add(a);
} else {
tempA = getAIfPresent(originalA, a.getaName());
if (tempA != null) {
bList = a.getbList().stream()
.filter(not(new HashSet<B>(tempA.getbList())::contains))
.collect(Collectors.toList());
if (bList != null) {
tempA.getbList().addAll(bList);
}
}
}
}
System.out.println("");
}
public static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
public static boolean containsName(final List<A> list, final String name){
return list.stream().map(A::getaName).filter(name::equals).findFirst().isPresent();
}
public static A getAIfPresent(final List<A> list, final String name) {
return list.stream().filter(x -> x.getaName().equalsIgnoreCase(name)).findFirst().orElse(null);
}
}