Java 8 Distinct by property

后端 未结 29 1793
傲寒
傲寒 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 23:05

    You can use the distinct(HashingStrategy) method in Eclipse Collections.

    List<Person> persons = ...;
    MutableList<Person> distinct =
        ListIterate.distinct(persons, HashingStrategies.fromFunction(Person::getName));
    

    If you can refactor persons to implement an Eclipse Collections interface, you can call the method directly on the list.

    MutableList<Person> persons = ...;
    MutableList<Person> distinct =
        persons.distinct(HashingStrategies.fromFunction(Person::getName));
    

    HashingStrategy is simply a strategy interface that allows you to define custom implementations of equals and hashcode.

    public interface HashingStrategy<E>
    {
        int computeHashCode(E object);
        boolean equals(E object1, E object2);
    }
    

    Note: I am a committer for Eclipse Collections.

    0 讨论(0)
  • 2020-11-21 23:05

    My solution in this listing:

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

    In my situation i want to find distinct values and put their in List.

    0 讨论(0)
  • 2020-11-21 23:07

    We can also use RxJava (very powerful reactive extension library)

    Observable.from(persons).distinct(Person::getName)
    

    or

    Observable.from(persons).distinct(p -> p.getName())
    
    0 讨论(0)
  • 2020-11-21 23:09

    If you want to List of Persons following would be the simple way

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

    Additionally, if you want to find distinct or unique list of names, not Person , you can do using following two method as well.

    Method 1: using distinct

    persons.stream().map(x->x.getName()).distinct.collect(Collectors.toList());
    

    Method 2: using HashSet

    Set<E> set = new HashSet<>();
    set.addAll(person.stream().map(x->x.getName()).collect(Collectors.toList()));
    
    0 讨论(0)
  • 2020-11-21 23:10

    You can use StreamEx library:

    StreamEx.of(persons)
            .distinct(Person::getName)
            .toList()
    
    0 讨论(0)
  • 2020-11-21 23:10

    I made a generic version:

    private <T, R> Collector<T, ?, Stream<T>> distinctByKey(Function<T, R> keyExtractor) {
        return Collectors.collectingAndThen(
                toMap(
                        keyExtractor,
                        t -> t,
                        (t1, t2) -> t1
                ),
                (Map<R, T> map) -> map.values().stream()
        );
    }
    

    An exemple:

    Stream.of(new Person("Jean"), 
              new Person("Jean"),
              new Person("Paul")
    )
        .filter(...)
        .collect(distinctByKey(Person::getName)) // return a stream of Person with 2 elements, jean and Paul
        .map(...)
        .collect(toList())
    
    0 讨论(0)
提交回复
热议问题