1

I am trying to compare two ArrayLists (i.e. ArrayList, list1 and ArrayList) testQueryValueand return the common elements between them. Below is what I have tried

private List<Loading> matchLists(List<Loading> list1 ,List<Test>  list2) {
        
    List<Loading> matchCriteria = new ArrayList<Loading>(list1);
    List<String>testQueryValue= list2.get(0).getTestQueryValues();
    for(Loading match: list1) {
    for(Sring test: testQueryValue){
        if (matchCriteria.contains(test)) {
            matchCriteria.add(test); // Error: The method add(Loading) in the type List<Loading> is not applicable for the arguments (String)
        }
    }
    return matchCriteria;
}

After editing this code as above getting the error as in the commented line in the code.

I know this question has already been asked several times. Based on the answers I have tried this approach and am unable to return the match. I am iterating through each elements of list1 which is a List of Loading, it contains nested arrays,and check if any element has test (subset of testQueryValue) in it? Then add test as the last element of matchCriteria which the method returns.

Thanks in advance for the help

16
  • "matchCriteria is returning null." - I don't see anything called matchCriteria that could return anything or that could be null. Do you mean the list is empty? ( Due to you using contains(match) it should never contain null directly). Commented Sep 20, 2021 at 8:16
  • Also, MatchCriteria, getList2QueryValues() etc. don't seem to be JDK classes, so what library are you using? You need to elaborate, add some example input and required output and ideally provide a minimal reproducible example. Commented Sep 20, 2021 at 8:19
  • @Thomas I have edited the code. The two lists are non empty i have debugged it and I see the values. Sorry that MatchCriteria reference variable I used it further for setting some lombok values. I removed in the edit and about providing the example values. I am not supposed to share as it is my projects data. Commented Sep 20, 2021 at 8:37
  • Which of List<String> or List<Loading> does your method return? Commented Sep 20, 2021 at 8:56
  • 1
    Well, ypu can't call matchCriteria.add(test); but would need to create a Loading instance out of test (how that works depends on the same things as I stated above). Assuming there's a Loading(String) constructor and good implementations of equals() and hashCode() you could do something like Loading testLoading = new Loading(test); if( !matchCriteria.contains(testLoading) ) { matchCriteria.add(testLoading); } - or better yet, use a Set (LinkedHashSet if you need to preserve order) since this would already handle duplicates, so no need for a !contains() check. Commented Sep 21, 2021 at 10:40

2 Answers 2

3

You can make use of retainAll() method

public class Person {

    private String name;
    private String surName;
    private int age;
    
    public Person(String name) {
        super();
        this.name = name;
        
    }
    public Person(String name, String surName, int age) {
        super();
        this.name = name;
        this.surName = surName;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", surName=" + surName + ", age=" + age + "]";
    }
    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        return Objects.equals(name, other.name);
    }
    
    
    
}

public class PersonTest {
    public static void main(String[] args) {

        List<Person> listofPerson = new ArrayList<>();
        listofPerson.add(new Person("Jane", "Brown", 18));
        listofPerson.add(new Person("John", "Smith", 20));
        listofPerson.add(new Person("Adam", "Williams", 18));
        
        List<Person> listofPerson2 = new ArrayList<>();
        listofPerson2.add(new Person("Jane", "Brown", 18));
        listofPerson2.add(new Person("John", "Smith", 20));
        listofPerson2.add(new Person("Adam", "Williams", 18));
        listofPerson2.add(new Person("Bravo", "Joan", 18));
        
        listofPerson2.retainAll(listofPerson);
        System.out.println(listofPerson2);

    }
}

Sample output

[Person [name=Jane, surName=Brown, age=18], Person [name=John, surName=Smith, age=20], Person [name=Adam, surName=Williams, age=18]]

Since I have overriden the equals method of parameter name It will retain all elements having same name in both the lists.

In your case, may be you can try the below method.

public static void main(String[] args) {

    List<Person> listofPerson = new ArrayList<>();
    listofPerson.add(new Person("Jane", "Brown", 18));
    listofPerson.add(new Person("John", "Smith", 20));
    listofPerson.add(new Person("Adam", "Williams", 18));

    List<String> listofPerson2 = new ArrayList<>();
    listofPerson2.add("Jane");
    listofPerson2.add("John");
    listofPerson2.add("Adam");
    listofPerson2.add("Bravo");
    Map<String, Person> personMap = listofPerson.stream()
            .collect(Collectors.toMap(Person::getName, Function.identity()));
    List<Person> finalList = listofPerson2.stream().filter(name -> personMap.containsKey(name))
            .map(name -> personMap.get(name)).collect(Collectors.toList());
    System.out.println(finalList.toString());
}
Sign up to request clarification or add additional context in comments.

5 Comments

but I am comparing one Person List and one String List.
I have editted my answer, Hope it resolves your issue.
List of Person1 "Jane", "Brown", 18 "John", "Smith", 20 "Adam", "Williams", 18 List of Person2 Jane Williams I want the output to be: "Jane", "Brown", 18, matchCriteria="Jane"
Sorry I did not get you.
Here the finalList will have the matching elements, use your logic to manipulate the output :)
1

Obviously, matchCriteria.add(test) isn't going to work for List<Loading> matchCriteria and String test.

Instead, you'd need to first create an instance of Loading using whatever test is. That would mean you'd need a constructor like Loading(String data) which is able to build a reasonable Loading instance.

In order to use matchCriteria.contains(Loading) the Loading class needs to have a reasonable implementation of equals(Object) and by contract hashCode() as well.

Finally, I assume you want to only add a Loading instance if it isn't already present in matchCriteria, i.e. you don't want duplicates. That would mean you'd be better off with a set, e.g. like this:

//LinkedHashSet keeps insert order
Set<Loading> matchCriteria = new LinkedHashSet<>(list1);

List<String>testQueryValue = list2.get(0).getTestQueryValues();
for(Loading match: list1) {
  for(Sring test: testQueryValue){
      matchCriteria.add(new Loading(test));
  }
}

return new ArrayList<>(matchCriteria);

If you want to keep using a list, your inner loop would probably need to look like this:

for(Sring test: testQueryValue){
  Loading testLoading = new Loading(test);
  if( !matchCriteria.contains(testLoading) ) {
    matchCriteria.add();
  }
}

Or, if you only want to create Loading instances if they are needed, use something like this:

Map<String, Loading> matches = new LinkedHashMap<>();
list1.forEach(loading -> matches.put(loading.getStringRepresentation, loading) );

for(Sring test: testQueryValue){
  matches.computeIfAbsent(test, key -> new Loading(key));
}

return new ArrayList<>(matches.values());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.