3

I want to use Java lambda expression for an intersection of two lists and then ever with lambda expression I want to delete from the list.

Example: I have

List<Person> first = new ArrayList<Person>(); 
List<Person> second = new ArrayList<Person>(); 

Suppose that both lists have some Person Object. I want put into List temp intersection of two list filtered by name for example:

List<Person> temp = new ArrayList<>();
for (Person one : first) {
     for (Person two : second) {                        
        if(one.getName.equals(two.getName)) {
                        temp.add(two);
         }
     }
}

Then I want to remove some Person from temp using a filter, for example, using the Surname.

for (Person tmp : temp) {
     for (Person one : first) {
        if (one.getSurname.equals(tmp.getSurname)) {
              temp.remove(tmp);
        }
     }
}

I want to use lambda expression, How i can do?

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
Fra87
  • 31
  • 1
  • 2

5 Answers5

3

You may do it like so,

Map<String, Set<String>> nameToSurname = second.stream().collect(
        Collectors.groupingBy(Person::getName, 
            Collectors.mapping(Person::getSurname, Collectors.toSet())));
List<Person> temp = first.stream().
    filter(p -> nameToSurname.containsKey(p.getName()))
    .filter(p -> !nameToSurname.get(p.getName()).contains(p.getSurname()))
    .collect(Collectors.toList());

First create a map from mame to all the surnames with that name using the second list. Then iterate over the first list, for each person, check whether there's a value in the map by passing the name as the key. If it does, then check whether the surnames matches that of the current person. If both the criteria are satisfied, then collect it into a container.

Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
3

Intersection between first and second:

List<Person> intersection = first.stream()
        .filter(p1 -> second.stream().anyMatch(p2 -> p2.getName().equals(p1.getName())))
        .collect(Collectors.toList());

Remove elements from myList based on elements from first:

first.stream()
    .filter(p1 -> myList.stream().anyMatch(p2 -> p1.getSurName().equals(p2.getSurName())))
    .forEach(myList::remove);
Alex M
  • 885
  • 9
  • 12
1

Both for-loops might be compressed into two Stream::filter methods:

List<Person> temp = second.stream()
    .filter(s ->  first.stream().anyMatch(f -> f.getName().equals(s.getName())))
    .filter(s -> !first.stream().anyMatch(f -> f.getSurame().equals(s.getSurame())))
    .collect(Collectors.toList());
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
0

Lambdas are not always the best solution.

You can use retainAll method from Collection<E>.

fist.retainAll(second);
dehasi
  • 2,644
  • 1
  • 19
  • 31
0

Here is solution by method reference and not.

second.stream()
     .filter(first.stream.map(Person::getName).collect(toSet())::contains)
     .filter(not(first.stream.map(Person::getSurname).collect(toSet())::contains))
     .collect(toList());

I didn't write the code in IDE. there may be some compiler errors.

user_3380739
  • 1
  • 14
  • 14