使用java 8流基于java对象的多个属性检索distinct元素

时间:2018-01-09 09:53:26

标签: java lambda java-8 java-stream

如何使用java 8 stream从基于多个条件的列表中获取distinct元素?

例如 - 让我们假设一个对象Person

class Person {
    Integer id;
    String name;
}

我想要一个包含idname唯一组合的列表 列表

中可以有多个具有相同ID和名称的记录

6 个答案:

答案 0 :(得分:5)

您可以创建自己独特的方法,例如:

private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Map<Object, Boolean> seen = new ConcurrentHashMap<>();
    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}

所以你可以将它与过滤器一起使用:

List<Person> persons = listPersons.stream()
         //@Holger suggest
        .filter(distinctByKey(pr -> Arrays.asList(pr.getId(), pr.getName())))
        .collect(toList());

看看这个:

如果您的名单是:

List<Person> listPersons = Arrays.asList(
        new Person(1, "person1"),
        new Person(1, "person5"),
        new Person(2, "person2"),
        new Person(1, "person1"),
        new Person(1, "person2"),
        new Person(1, "person1"),
        new Person(3, "person3")
);

输出

Person{id=1, name=person1}
Person{id=1, name=person5}
Person{id=2, name=person2}
Person{id=1, name=person2}
Person{id=3, name=person3}

答案 1 :(得分:2)

为您的课程覆盖hashCode()equals()方法,然后您可以执行以下操作:

Set<Person> result = persons.stream().collect(Collectors.toSet());

Set是一个不允许重复的数据结构,所以这样你只会有唯一的元素。

这是一个解决方案:https://ideone.com/e.js/G7T2rH

答案 2 :(得分:0)

方法Stream.distinct()方法,返回唯一值流(基于Object.equals)

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#distinct--

答案 3 :(得分:0)

我不确定,你究竟在寻找什么,但我前段时间遇到了类似的问题,这可能会有所帮助。

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

public class Person {

public int id;
public String name;
public static List<String> combinedIds;

public Person(int id, String name) {
    this.id = id;
    this.name = name;
}

public int getId() {
    return id;
}

public String getName() {
    return name;
}

public static String getCombinedUuid(Person person) {
    return person.getName() + person.getId();
}

public static void main(String[] args) {

    List<String> combinedIDs = new ArrayList<String>();

    Person person = new Person(12345, "Doe");

    String generatedUuid = getCombinedUuid(person);

    combinedIDs.add(generatedUuid);

    System.out.println(combinedIDs.get(0).toString());

}

}

答案 4 :(得分:0)

您可以先过滤列表以获取符合条件的元素,然后使用distinct。

List<element> getDistinctForCrit(Filter<element> pred) {
 //assuming list is already available in this class
 return list.stream().filter(pred).distinct().collect(Collectors.toList())
}

您可以将过滤条件传递给此函数,然后distinct将为您获取唯一值。

distinct()根据对象比较产生不同的值。

因此,您应该在类

的equals()方法中给出唯一性逻辑

答案 5 :(得分:0)

下面是获取解决方案的步骤。

  1. 您需要在Person类中实现equals和hashcode以进行相等性检查。 如果您在类中重写了这些方法,则每当进行相等检查时,都会调用Person中实现的方法,并将始终返回唯一的结果。

     class Person {
    
     Integer id;
     String name;
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         Person p = (Person) o;
         return id == p.id && Objects.equals(name, p.name);
     }
     @Override
     public int hashCode() {
     return Objects.hash(id, name);
    

    }

}

  1. 使用以下任何一种方法来获得与众不同的Person值:

    a)。使用Set是因为Set仅包含唯一值。这是一个无序的集合。

     Set<Person> set=new HashSet<Person>();
    
      for(Person c:list){
         set.add(c);
         }
    

    b)。使用Java8 Stream API:

     List<Person> unique = list.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparingInt(Person::getId))),
                     ArrayList::new));
    

    c)。如果需要有序收集:

     LinkedHashSet<Person> lset=new LinkedHashSet<Person>();
     for(Personc:list){
         lset.add(c);
     }
    

    d)Java 8 Stream API方法:

     List<Person> ll= list.stream().distinct().collect(Collectors.toList());
     ll.forEach((k) -> System.out.println(k.getId()+" & "+k.getName()));