Java 8 Distinct by property

后端 未结 29 1794
傲寒
傲寒 2020-11-21 22:35

In Java 8 how can I filter a collection using the Stream API by checking the distinctness of a property of each object?

For example I have a list of

相关标签:
29条回答
  • 2020-11-21 22:58

    You can wrap the person objects into another class, that only compares the names of the persons. Afterward, you unwrap the wrapped objects to get a person stream again. The stream operations might look as follows:

    persons.stream()
        .map(Wrapper::new)
        .distinct()
        .map(Wrapper::unwrap)
        ...;
    

    The class Wrapper might look as follows:

    class Wrapper {
        private final Person person;
        public Wrapper(Person person) {
            this.person = person;
        }
        public Person unwrap() {
            return person;
        }
        public boolean equals(Object other) {
            if (other instanceof Wrapper) {
                return ((Wrapper) other).person.getName().equals(person.getName());
            } else {
                return false;
            }
        }
        public int hashCode() {
            return person.getName().hashCode();
        }
    }
    
    0 讨论(0)
  • 2020-11-21 22:58
    Set<YourPropertyType> set = new HashSet<>();
    list
            .stream()
            .filter(it -> set.add(it.getYourProperty()))
            .forEach(it -> ...);
    
    0 讨论(0)
  • 2020-11-21 22:59

    The Most simple code you can write:

        persons.stream().map(x-> x.getName()).distinct().collect(Collectors.toList());
    
    0 讨论(0)
  • 2020-11-21 23:00

    I recommend using Vavr, if you can. With this library you can do the following:

    io.vavr.collection.List.ofAll(persons)
                           .distinctBy(Person::getName)
                           .toJavaSet() // or any another Java 8 Collection
    
    0 讨论(0)
  • 2020-11-21 23:01

    Extending Stuart Marks's answer, this can be done in a shorter way and without a concurrent map (if you don't need parallel streams):

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

    Then call:

    persons.stream().filter(distinctByKey(p -> p.getName());
    
    0 讨论(0)
  • 2020-11-21 23:04

    Maybe will be useful for somebody. I had a little bit another requirement. Having list of objects A from 3rd party remove all which have same A.b field for same A.id (multiple A object with same A.id in list). Stream partition answer by Tagir Valeev inspired me to use custom Collector which returns Map<A.id, List<A>>. Simple flatMap will do the rest.

     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)); }
    
    0 讨论(0)
提交回复
热议问题