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

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

persons.stream().distinct();

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

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

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


当前回答

Set<YourPropertyType> set = new HashSet<>();
list
        .stream()
        .filter(it -> set.add(it.getYourProperty()))
        .forEach(it -> ...);

其他回答

也许会对某人有用。我还有一个要求。从第三方对象A列表中删除所有具有相同A.b字段的相同A.id的对象(列表中具有相同A.id的多个A对象)。流分区的答案由Tagir Valeev启发我使用自定义收集器返回Map<A。id列表< > >。简单的flatMap将完成其余的工作。

 public static <T, K, K2> Collector<T, ?, Map<K, List<T>>> groupingDistinctBy(Function<T, K> keyFunction, Function<T, K2> distinctFunction) {
    return groupingBy(keyFunction, Collector.of((Supplier<Map<K2, T>>) HashMap::new,
            (map, error) -> map.putIfAbsent(distinctFunction.apply(error), error),
            (left, right) -> {
                left.putAll(right);
                return left;
            }, map -> new ArrayList<>(map.values()),
            Collector.Characteristics.UNORDERED)); }

另一种方法是将人名作为键放在地图中:

persons.collect(Collectors.toMap(Person::getName, p -> p, (p, q) -> p)).values();

注意,如果名称重复,则保留的Person将是第一个遇到的Person。

扩展Stuart Marks的回答,这可以用更短的方式完成,不需要并发映射(如果你不需要并行流):

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    final Set<Object> seen = new HashSet<>();
    return t -> seen.add(keyExtractor.apply(t));
}

然后调用:

persons.stream().filter(distinctByKey(p -> p.getName());

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

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());

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

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

    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'}