Java:使用Stream API在嵌套列表中查找公共项

Jai*_*Jai 1 java java-8 java-stream

比方说我有一个List<List<Animal>> animals.此嵌套列表表示每个地方包含动物列表的地点列表.

我需要找出至少出现在两个不同地方的动物类型列表.我知道我可以做正常的循环并做到这一点.有什么办法可以通过Stream API完成吗?

例:

List<List<Animal>> animals = new ArrayList<>();
animals.add(Arrays.asList(new Dog(), new Cat()));
animals.add(Arrays.asList(new Dog(), new Bird()));
animals.add(Arrays.asList(new Bird()));
Run Code Online (Sandbox Code Playgroud)

预期(相当于):

List<Class<? extends Animal>> animalTypes = Arrays.asList(Dog.class, Bird.class);
Run Code Online (Sandbox Code Playgroud)

至于尝试,我只设法将内部列表转换为一组类:

animals.stream().map(place -> place.stream().map(animal -> animal.getClass()).collect(Collectors.toSet()));
Run Code Online (Sandbox Code Playgroud)

更新

没有Stream API的代码:

final List<List<Animal>> animals = new ArrayList<>();
animals.add(Arrays.asList(new Dog(), new Cat()));
animals.add(Arrays.asList(new Dog(), new Bird()));
animals.add(Arrays.asList(new Bird()));

final Map<Class<? extends Animal>, Integer> count = new HashMap<>();

for (final List<Animal> place : animals) {
    final Set<Class<? extends Animal>> uniqueTypes = new HashSet<>();

    for (final Animal animal : place) {
        uniqueTypes.add(animal.getClass());
    }

    for (final Class<? extends Animal> type : uniqueTypes) {
        if (!count.containsKey(type))
        {
            count.put(type, 1);
        }
        else
        {
            count.put(type, count.get(type).intValue() + 1);
        }
    }
}

final List<Class<? extends Animal>> typesAppearingAtLeastAtTwoPlaces = new ArrayList<>();

for (final Class<? extends Animal> type : count.keySet()) {
    if (count.get(type).intValue() >= 2) {
        typesAppearingAtLeastAtTwoPlaces.add(type);
    }
}

System.out.println(typesAppearingAtLeastAtTwoPlaces);
Run Code Online (Sandbox Code Playgroud)

输出:

[class Test$Dog, class Test$Bird]
Run Code Online (Sandbox Code Playgroud)

Mis*_*sha 5

首先,计算所有动物,然后选择出现不止一次的动物:

import static java.util.stream.Collectors.*;
.....

Map<Class<? extends Animal>, Long> animalCounts = animals.stream()
        .flatMap(
                lst -> lst.stream()
                    .map(a -> a.getClass())
                    .distinct()   // in case several of the same animal are in the same place
        )
        .collect(groupingBy(x -> x, counting()));

List<Class<? extends Animal>> animalTypes = animalCounts.entrySet().stream()
        .filter(e -> e.getValue() > 1)
        .map(Map.Entry::getKey)
        .collect(toList());
Run Code Online (Sandbox Code Playgroud)