Find element matching in 2 lists using java 8 stream

时光总嘲笑我的痴心妄想 提交于 2019-12-03 03:03:43

Define yourself a key object that holds and compares the desired properties. In this simple case, you may use a small list whereas each index corresponds to one property. For more complex cases, you may use a 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 mapping function. you may use the 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 may lead to poor performance when you have rather large lists. When you have large lists (or can’t predict their sizes), you should use an intermediate Set to accelerate the lookup (changing the task’s time complexity 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 examples above, each match gets printed. If you are only interested in whether such a match exists, you may 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);

A simple way to do that is to override equals and hashCode. Since I assume the equality between Person must also consider the id field, you can wrap this instance into a PersonWrapper which will implement the correct equals and hashCode (i.e. only check the name and age fields):

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 then 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 the list2 into a Set of wrapped persons. The goal of having a Set is to have a constant-time contains operation for better performance.

Then, the list1 is filtered. Every element found in set2 is kept and if there is an element left (that is to say, if findFirst() returns a non empty Optional), it means an element was found.

Brute force, but pure java 8 solution will be this:

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 join 2 lists. limit is used as we are interested in first match only, in which case, we do not need to traverse further.

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

Here's the Person class code

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 stream to get the intersection like so. common will contain all Person objects where name and age are the same.

List<Person> common = list1
      .stream()
      .filter(list2::contains)
      .collect(Collectors.toList());
<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/

This would 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() takes Consumer, we have no way of returning and PresentOrNot {} is a workaround. Aside: Where didi you get such a requirement :)

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

for(Person person1 : list1) {
    for(Person person2 : list2) {
        if(person1.getName().equals(person2.getName()) && 
                person1.getAge().equals(person2.getAge())) {
            //your code
        }
    }
}
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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!