Find matching elements in 2 lists using java 8 thread

My business:

class Person { String id ; String name; String age; } List<Person> list1 = {p1,p2, p3}; List<Person> list2 = {p4,p5, p6}; 

I want to know if there is a person in list1 with the same name and age in list2 , but don't mind id .

What is the best and fastest way?

+5
source share
8 answers

Define yourself a key object that contains and compares the required properties. In this simple case, you can use a small list, while each index corresponds to one property. For more complex cases, you can use Map (using property names as keys) or a dedicated class:

 Function<Person,List<Object>> toKey=p -> Arrays.asList(p.getName(), p.getAge()); 

Having such a display function. you can use a simple solution:

 list1.stream().map(toKey) .flatMap(key -> list2.stream().map(toKey).filter(key::equals)) .forEach(key -> System.out.println("{name="+key.get(0)+", age="+key.get(1)+"}")); 

which can lead to poor performance with fairly large lists. If you have large lists (or predict their sizes), you should use the intermediate Set to speed up the search (changing the complexity of the task time from O(n²) to O(n) ):

 list2.stream().map(toKey) .filter(list1.stream().map(toKey).collect(Collectors.toSet())::contains) .forEach(key -> System.out.println("{name="+key.get(0)+", age="+key.get(1)+"}")); 

In the above examples, each match is printed. If you are only interested in such a match, you can use either:

 boolean exists=list1.stream().map(toKey) .anyMatch(key -> list2.stream().map(toKey).anyMatch(key::equals)); 

or

 boolean exists=list2.stream().map(toKey) .anyMatch(list1.stream().map(toKey).collect(Collectors.toSet())::contains); 
+3
source

An easy way to do this is to override equals and hashCode . Since I assume that the equality between Person should also take into account the id field, you can wrap this instance in PersonWrapper , which will implement the correct equals and hashCode (i.e. Check only name and age tags):

 class PersonWrapper { private Person person; private PersonWrapper(Person person) { this.person = person; } public static PersonWrapper wrap(Person person) { return new PersonWrapper(person); } public Person unwrap() { return person; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } PersonWrapper other = (PersonWrapper) obj; return person.name.equals(other.person.name) && person.age.equals(other.person.age); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + person.name.hashCode(); result = prime * result + person.age.hashCode(); return result; } } 

With such a class, you can have the following:

 Set<PersonWrapper> set2 = list2.stream().map(PersonWrapper::wrap).collect(toSet()); boolean exists = list1.stream() .map(PersonWrapper::wrap) .filter(set2::contains) .findFirst() .isPresent(); System.out.println(exists); 

This code converts list2 to Set Wrapped Faces. The goal of having Set is to have a contains operation with constant time for better performance.

Then list1 is filtered. Each element found in set2 is saved, and if there is an element on the left (that is, if findFirst() returns a nonempty Optional ), this means that the element is found.

+7
source

Well, if you don't care about the id field, you can use the equals method to solve this problem.

Here is the Person class

 public class Person { private String id ; private String name; private String age; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person sample = (Person) o; if (!name.equals(sample.name)) return false; return age.equals(sample.age); } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + age.hashCode(); return result; } } 

Now you can use the stream to get such an intersection. common will contain all Person objects where name and age match.

 List<Person> common = list1 .stream() .filter(list2::contains) .collect(Collectors.toList()); 
+2
source

Brute force but pure java 8 solution would be as follows:

 boolean present = list1 .stream() .flatMap(x -> list2 .stream() .filter(y -> x.getName().equals(y.getName())) .filter(y -> x.getAge().equals(y.getAge())) .limit(1)) .findFirst() .isPresent(); 

Here, flatmap is used to combine two lists. limit used because we are only interested in the first match, in which case we do not need to go any further.

+2
source

This will work:

 class PresentOrNot {boolean isPresent = false;}; final PresentOrNot isPresent = new PresentOrNot (); l1.stream().forEach(p -> { isPresent.isPresent = isPresent.isPresent || l2.stream() .filter(p1 -> p.name.equals(p1.name) && p.age.equals(p1.age)) .findFirst() .isPresent(); }); System.err.println(isPresent.isPresent); 

Since forEach() accepts Consumer, we cannot return, and PresentOrNot {} is a workaround. In addition: where do you have such a requirement :)

+1
source
 <h3>Find List of Object passing String of Array Using java 8?</h3> [Faiz Akram][1] <pre> public class Student { private String name; private Integer age; public Student(String name, Integer age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } </pre> // Main Class <pre> import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class JavaLamda { public static void main(String[] k) { List<Student> stud = new ArrayList<Student>(); stud.add(new Student("Faiz", 1)); stud.add(new Student("Dubai", 2)); stud.add(new Student("Akram", 5)); stud.add(new Student("Rahul", 3)); String[] name= {"Faiz", "Akram"}; List<Student> present = Arrays.asList(name) .stream() .flatMap(x -> stud .stream() .filter(y -> x.equalsIgnoreCase(y.getName()))) .collect(Collectors.toList()); System.out.println(present); } } </pre> OutPut //[ Student@404b9385 , Student@6d311334 ] [1]: http://faizakram.com/blog/find-list-object-passing-string-array-using-java-8/ 
+1
source

You need to iterate over the two lists and compare the attributes.

 for(Person person1 : list1) { for(Person person2 : list2) { if(person1.getName().equals(person2.getName()) && person1.getAge().equals(person2.getAge())) { //your code } } } 
0
source
 public static void main(String[] args) { OTSQuestions ots = new OTSQuestions(); List<Attr> attrs = ots.getAttrs(); List<String> ids = new ArrayList<>(); ids.add("101"); ids.add("104"); ids.add("102"); List<Attr> finalList = attrs.stream().filter( attr -> ids.contains(attr.getId())) .collect(Collectors.toList()); } public class Attr { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } private List<Attr> getAttrs() { List<Attr> attrs = new ArrayList<>(); Attr attr = new Attr(); attr.setId("100"); attr.setName("Yoga"); attrs.add(attr); Attr attr1 = new Attr(); attr1.setId("101"); attr1.setName("Yoga1"); attrs.add(attr1); Attr attr2 = new Attr(); attr2.setId("102"); attr2.setName("Yoga2"); attrs.add(attr2); Attr attr3 = new Attr(); attr3.setId("103"); attr3.setName("Yoga3"); attrs.add(attr3); Attr attr4 = new Attr(); attr4.setId("104"); attr4.setName("Yoga4"); attrs.add(attr4); return attrs; } 
0
source

Source: https://habr.com/ru/post/1237557/


All Articles