Java流 - 查找唯一元素

时间:2017-04-07 17:16:18

标签: java java-8 java-stream

我有List<Person> persons = new ArrayList<>();,我想列出所有唯一名称。我的意思是,如果有&#34; John&#34;,&#34; Max&#34;,&#34; John&#34;,&#34; Greg&#34;那么我只想列出&#34; Max&#34;和#34; Greg&#34;。有没有办法用Java流做到这一点?

8 个答案:

答案 0 :(得分:8)

我们可以使用流和Collectors.groupingBy来计算每个名称的出现次数 - 然后过滤出现多次出现的任何名称:

    List<String> res = persons.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet()
            .stream()
            .filter(e -> e.getValue() == 1)
            .map(e -> e.getKey())
            .collect(Collectors.toList());

    System.out.println(res); // [Max, Greg]

答案 1 :(得分:4)

首先猜测解决方案。

persons.stream()
       .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
       .entrySet()
       .stream()
       .filter(entry -> entry.getValue() == 1)
       .map(Map.Entry::getKey)
       .collect(Collectors.toList())

答案 2 :(得分:2)

List persons = new ArrayList();
    persons.add("Max");
    persons.add("John");
    persons.add("John");
    persons.add("Greg");

    persons.stream()
             .filter(person -> Collections.frequency(persons, person) == 1)
             .collect(Collectors.toList());

答案 3 :(得分:1)

这应该删除所有重复的元素。

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

        persons.add("John");
        persons.add("John");
        persons.add("MAX");
        persons.add("Greg");

        Set<String> set = new HashSet<String>();

        Set<String> duplicateSet = new HashSet<String>();

        for (String p : persons) {

            if (!set.add(p)) {
                duplicateSet.add(p);
            }
        }

        System.out.println(duplicateSet.toString());
        set.removeAll(duplicateSet);
        System.out.println(set.toString());

答案 4 :(得分:1)

您可以使用Collections.frequency检查列表中的元素出现情况,如下所示,以过滤重复项:

List<String> listInputs = new ArrayList<>();
//add your users
List<String> listOutputs = new ArrayList<>();
for(String value : listInputs) {
     if(Collections.frequency(listInputs, value) ==1) {
         listOutputs.add(value);
     }
}
System.out.println(listOutputs);

答案 5 :(得分:0)

这是一篇旧帖子,但我想提出另一种基于自定义收集器的方法:

public static <T> Collector<T, ?, List<T>> excludingDuplicates() {
    return Collector.<T, Map<T, Boolean>, List<T>>of(
        LinkedHashMap::new,
        (map, elem) -> map.compute(elem, (k, v) -> v == null),
        (left, right) -> {
            right.forEach((k, v) -> left.merge(k, v, (o, n) -> false));
            return left;
        },
        m -> m.keySet().stream().filter(m::get).collect(Collectors.toList()));
}

这里我使用Collector.of来创建一个自定义收集器,它将在LinkedHashMap上累积元素:如果该元素不作为键存在,则其值为true,否则它将是false。合并函数仅应用于并行流,并通过尝试将right映射的每个条目放在left映射中,将right映射合并到left映射中,将已存在的键的值更改为false。最后,finisher函数返回一个列表,其中包含值为true的地图键。

此方法可按如下方式使用:

List<String> people = Arrays.asList("John", "Max", "John", "Greg");

List<String> result = people.stream().collect(excludingDuplicates());

System.out.println(result); // [Max, Greg]

这是另一种比使用自定义收集器更简单的方法:

Map<String, Boolean> duplicates = new LinkedHashMap<>();
people.forEach(elem -> duplicates.compute(elem, (k, v) -> v != null));
duplicates.values().removeIf(v -> v);

Set<String> allUnique = duplicates.keySet();

System.out.println(allUnique); // [Max, Greg]

答案 6 :(得分:0)

您可以尝试以下代码。

    List<Person> uniquePersons = personList.stream()
            .collect(Collectors.groupingBy(person -> person.getName()))
            .entrySet().stream().filter(stringListEntry -> stringListEntry.getValue().size()==1)
            .map(stringListEntry -> { return stringListEntry.getValue().get(0); })
            .collect(Collectors.toList());

答案 7 :(得分:0)

这是我的解决方案:

List<String> persons = new ArrayList<>();
persons.add("John");
persons.add("John");
persons.add("MAX");
persons.add("Greg");
persons.stream()
          .distinct()
          .sorted()
          .collect(Collectors.toList());