使用java8从两个java列表中获取唯一的用户定义对象

时间:2017-11-22 05:58:16

标签: java collections java-stream

我有一个名为Employee的用户定义对象,如下所示,有两个不同的列表,其中包含Employee对象。

在两个不同的列表中,我需要根据对象中的name字段找到唯一对象。 最终列表应仅包含一个名称为 c 的对象。

请建议我如何使用java 8进行操作?

import java.util.ArrayList;
import java.util.List;

class Employee{
    private String name;
    private String age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }   
}


public class UniqueObjects {

    public static void main(String[] args) {
        List<Employee> empOneList= new ArrayList<Employee>();
        List<Employee> empTwoList= new ArrayList<Employee>();

        Employee empOne= new Employee();        
        empOne.setName("a");
        empOne.setAge("23");
        empOneList.add(empOne);

        Employee emptwo= new Employee();        
        emptwo.setName("b");
        emptwo.setAge("24");
        empOneList.add(emptwo);

        Employee em= new Employee();
        em.setName("a");
        em.setAge("23");
        empTwoList.add(em);

        Employee emp1= new Employee();
        emp1.setName("d");
        emp1.setAge("24");
        empTwoList.add(emp1);    
    }
}

3 个答案:

答案 0 :(得分:1)

我认为您的问题是如何在两个列表中找到具有给定名称的单个员工。如果是这种情况,那么最简单的事情就是流式传输两个列表并筛选出唯一的员工:

Optional<Employee> employee = Stream.concat(list1.stream(), list2.stream())
    .filter(e -> e.getName().equals(name)).findAny();

如果您希望两个列表中的对象都具有该名称,则:

List<Employee> employees = Stream.concat(list1.stream(), list2.stream))
    .filter(e -> e.getName().equals(name)).collect(Collectors.toList());

答案 1 :(得分:0)

要根据名称字段查找唯一对象,您可以使用以下代码:

Map<String, List<Employee>> employeeMap = Stream.concat(empOneList.stream(), empTwoList.stream())
                .collect(Collectors.groupingBy(Employee::getName, Collectors.toList()));
  1. 使用番石榴

    Collection<List<Employee>> employeesWithUniqueName =
            Maps.filterValues(employeeMap, empList -> empList.size() == 1).values();
    
  2. 使用Stream API

    Collection<Employee> employeesWithUniqueName =
            employeeMap.values().stream().filter(empList -> empList.size() == 1)
                    .flatMap(List::stream)
                    .collect(Collectors.toList());
    

答案 2 :(得分:0)

如果我正确理解了您的问题,那么您正在寻找仅出现在其中一个列表中但不同时出现在这两个列表中的元素。这称为disjunctive union。有一种非常简单的方法可以使用Collection.removeAll()检索它:

public static <T> Set<T> getdisjunctiveUnion(Set<T> set1, Set<T> set2)
{
    Collection<Employee> copy1 = new HashSet<>(set1);
    Collection<Employee> copy2 = new HashSet<>(set2);

    copy1.removeAll(set1);
    copy2.removeAll(set2);

    copy1.addAll(copy2);
    return copy1;
}

请注意,这需要equalshashCode基于Employee实现name(您的IDE会为您执行此操作):

@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override
public boolean equals(Object obj)
{
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    Employee other = (Employee) obj;
    if (name == null && other.name != null) return false;
    else if (!name.equals(other.name)) return false;
    return true;
}

如果您不想实现这些方法,可以使用新方法Collection.removeIf()

copy1.removeIf(emp1 -> set2.stream().anyMatch(emp2 -> emp2.getName().equals(emp1.getName())));
copy2.removeIf(emp2 -> set1.stream().anyMatch(emp1 -> emp1.getName().equals(emp2.getName())));

或者,您可以使用流来过滤集合(请谨慎使用noneMatch而不是anyMatch),而不是复制/删除:

Collection<Employee> disjunctiveUnion = new HashSet<>();
set1.stream()
    .filter(emp1 -> set2.stream().noneMatch(emp2 -> emp2.getName().equals(emp1.getName())))
    .forEach(disjunctiveUnion::add);
set2.stream()
    .filter(emp2 -> set1.stream().noneMatch(emp1 -> emp1.getName().equals(emp2.getName())))
    .forEach(disjunctiveUnion::add);
return disjunctiveUnion;