在Java 8中,我如何使用流API通过检查每个对象的属性的清晰度来过滤一个集合?

例如,我有一个Person对象列表,我想删除同名的人,

persons.stream().distinct();

将对Person对象使用默认的相等性检查,所以我需要这样的东西,

persons.stream().distinct(p -> p.getName());

不幸的是,distinct()方法没有这样的重载。如果不修改Person类内部的相等检查,是否可以简洁地做到这一点?


当前回答

这个解是什么呢?

只有当你的键实现了Equal时它才会起作用大多数基类型都是这样,但它更简单一点。

person.stream()。map(person -> p.getName()).distinct()

其他回答

这个解是什么呢?

只有当你的键实现了Equal时它才会起作用大多数基类型都是这样,但它更简单一点。

person.stream()。map(person -> p.getName()).distinct()

我在这个清单中的解决方案:

List<HolderEntry> result ....

List<HolderEntry> dto3s = new ArrayList<>(result.stream().collect(toMap(
            HolderEntry::getId,
            holder -> holder,  //or Function.identity() if you want
            (holder1, holder2) -> holder1 
    )).values());

在我的情况下,我想找到不同的值,并把它们放在列表。

另一个解决方案,使用Set。也许不是理想的解决方案,但有效吗

Set<String> set = new HashSet<>(persons.size());
persons.stream().filter(p -> set.add(p.getName())).collect(Collectors.toList());

或者如果可以修改原始列表,可以使用removeIf方法

persons.removeIf(p -> !set.add(p.getName()));

有很多方法,这一个也会有帮助-简单,干净和清晰

    List<Employee> employees = new ArrayList<>();

    employees.add(new Employee(11, "Ravi"));
    employees.add(new Employee(12, "Stalin"));
    employees.add(new Employee(23, "Anbu"));
    employees.add(new Employee(24, "Yuvaraj"));
    employees.add(new Employee(35, "Sena"));
    employees.add(new Employee(36, "Antony"));
    employees.add(new Employee(47, "Sena"));
    employees.add(new Employee(48, "Ravi"));

    List<Employee> empList = new ArrayList<>(employees.stream().collect(
                    Collectors.toMap(Employee::getName, obj -> obj,
                    (existingValue, newValue) -> existingValue))
                   .values());

    empList.forEach(System.out::println);


    //  Collectors.toMap(
    //  Employee::getName, - key (the value by which you want to eliminate duplicate)
    //  obj -> obj,  - value (entire employee object)
    //  (existingValue, newValue) -> existingValue) - to avoid illegalstateexception: duplicate key

Output - toString()重载

Employee{id=35, name='Sena'}
Employee{id=12, name='Stalin'}
Employee{id=11, name='Ravi'}
Employee{id=24, name='Yuvaraj'}
Employee{id=36, name='Antony'}
Employee{id=23, name='Anbu'}

基于@josketres的回答,我创建了一个通用的实用方法:

您可以通过创建一个Collector使其对Java 8更加友好。

public static <T> Set<T> removeDuplicates(Collection<T> input, Comparator<T> comparer) {
    return input.stream()
            .collect(toCollection(() -> new TreeSet<>(comparer)));
}


@Test
public void removeDuplicatesWithDuplicates() {
    ArrayList<C> input = new ArrayList<>();
    Collections.addAll(input, new C(7), new C(42), new C(42));
    Collection<C> result = removeDuplicates(input, (c1, c2) -> Integer.compare(c1.value, c2.value));
    assertEquals(2, result.size());
    assertTrue(result.stream().anyMatch(c -> c.value == 7));
    assertTrue(result.stream().anyMatch(c -> c.value == 42));
}

@Test
public void removeDuplicatesWithoutDuplicates() {
    ArrayList<C> input = new ArrayList<>();
    Collections.addAll(input, new C(1), new C(2), new C(3));
    Collection<C> result = removeDuplicates(input, (t1, t2) -> Integer.compare(t1.value, t2.value));
    assertEquals(3, result.size());
    assertTrue(result.stream().anyMatch(c -> c.value == 1));
    assertTrue(result.stream().anyMatch(c -> c.value == 2));
    assertTrue(result.stream().anyMatch(c -> c.value == 3));
}

private class C {
    public final int value;

    private C(int value) {
        this.value = value;
    }
}