Apple
Apple

Reputation: 73

Finding unique strings in two arraylists of objects

I have two arraylists of objects, I want to know which strings are unique to arraylist 1, and which strings are unique to arraylist 2. What I have come up with is the forloop below, which I have to implement twice, reversing the positions of the arraylists. I'm hopeful someone can suggest a more elegant way to do this.

Per request, a bunch more stuff I guess I wrongfully assumed was implied in the code-snippet itself. And the output this produces is:

grape doesn't exist in second arrayList

pineapple doesn't exist in first arrayList

Works great, everything is great, but, per above, I'm hopeful someone with more knowledge of streams/java in general can provide a better solution than just running my stream twice, with the inputs reversed.

import java.util.ArrayList;

public class CompareTwoArrays {

    ArrayList<MyCustomObject> firstArrayListOfObjects = new ArrayList<>();
    ArrayList<MyCustomObject> secondArrayListOfObjects = new ArrayList<>();

    public void superSpecificExampleMethod() {
        firstArrayListOfObjects.add(new MyCustomObject(1, 1, "apple"));
        firstArrayListOfObjects.add(new MyCustomObject(1, 1, "orange"));
        firstArrayListOfObjects.add(new MyCustomObject(1, 1, "banana"));
        firstArrayListOfObjects.add(new MyCustomObject(1, 1, "grape"));
        secondArrayListOfObjects.add(new MyCustomObject(1, 1, "apple"));
        secondArrayListOfObjects.add(new MyCustomObject(1, 1, "pineapple"));
        secondArrayListOfObjects.add(new MyCustomObject(1, 1, "orange"));
        secondArrayListOfObjects.add(new MyCustomObject(1, 1, "banana"));

        for (MyCustomObject object : firstArrayListOfObjects) {
            if (!secondArrayListOfObjects.stream().map(MyCustomObject::getString).filter(object.getString()::equals).findFirst().isPresent()) {
                System.out.println(object.getString() + " doesn't exist in second arrayList");
            }
        }

        for (MyCustomObject object : secondArrayListOfObjects) {
            if (!firstArrayListOfObjects.stream().map(MyCustomObject::getString).filter(object.getString()::equals).findFirst().isPresent()) {
                System.out.println(object.getString() + " doesn't exist in first arrayList");
            }
        }
    }
}

class MyCustomObject {

    private int randomIntOne;
    private int randomIntTwo;
    private String string;

    public MyCustomObject(int randomIntOne, int randomIntTwo, String string) {
        this.randomIntOne = randomIntOne;
        this.randomIntTwo = randomIntTwo;
        this.string = string;
    }

    public String getString() {
        return string;
    }
}

Upvotes: 0

Views: 828

Answers (1)

Nowhere Man
Nowhere Man

Reputation: 19565

Assuming there are two array lists of objects MyObject containing strings:

List<MyObject> listOne = new ArrayList<>(Arrays.asList(
    new MyObject("aaa"), new MyObject("bbb"), new MyObject("ccc"), new MyObject("ddd")
));

List<MyObject> listTwo = new ArrayList<>(Arrays.asList(
    new MyObject("fff"), new MyObject("bbb"), new MyObject("ggg"), new MyObject("ddd")
));

To find "unique" objects in listOne that is those which are not available in listTwo there are several ways:

  1. Use List::removeAll providing that the methods equals and hashCode are properly implemented in this class

removeAll should be applied to a copy of listOne

List<MyObject> diffOneMinusTwo = new ArrayList<>(listOne); // copy
diffOneMinusTwo.removeAll(listTwo); // ["aaa", "ccc"]
  1. Use List::removeIf accepting a predicate and using a set of the strings contained in the objects of listTwo:
Set<String> listTwoStrings = listTwo
    .stream()
    .map(MyObject::getString)
    .collect(Collectors.toSet);
List<MyObject> diffOneMinusTwo = new ArrayList<>(listOne); // copy
diffOneMinusTwo.removeIf(x -> listTwoStrings.contains(x.getString()));
  1. Use Stream API filter and collect - no copy is needed here but a temporary set of strings is used
List<MyObject> diffOneMinusTwo = listOne
        .stream()
        .filter(x -> !listTwoStrings.contains(x.getString()))
        .collect(Collectors.toList());

In Java 11 there is static Predicate::not method so the stream version may look like this (if hashCode and equals are implemented properly):

List<MyObject> diffOneMinusTwo = listOne
        .stream()
        .filter(Predicate.not(listTwo::contains)) // using method reference
        .collect(Collectors.toList());

The difference between listTwo and listOne can be created vice versa.

Upvotes: 1

Related Questions