猿问

Java:使用Stream API在嵌套列表中查找常见项目

假设我有一个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()));

预期(等同于):


List<Class<? extends Animal>> animalTypes = Arrays.asList(Dog.class, Bird.class);

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


animals.stream().map(place -> place.stream().map(animal -> animal.getClass()).collect(Collectors.toSet()));

更新

在没有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);

输出:


[class Test$Dog, class Test$Bird]


素胚勾勒不出你
浏览 231回答 3
3回答

繁星coding

首先,对所有动物进行计数,然后选择出现多次的动物:import static java.util.stream.Collectors.*;.....Map<Class<? extends Animal>, Long> animalCounts = animals.stream()&nbsp; &nbsp; &nbsp; &nbsp; .flatMap(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lst -> lst.stream()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(a -> a.getClass())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .distinct()&nbsp; &nbsp;// in case several of the same animal are in the same place&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; .collect(groupingBy(x -> x, counting()));List<Class<? extends Animal>> animalTypes = animalCounts.entrySet().stream()&nbsp; &nbsp; &nbsp; &nbsp; .filter(e -> e.getValue() > 1)&nbsp; &nbsp; &nbsp; &nbsp; .map(Map.Entry::getKey)&nbsp; &nbsp; &nbsp; &nbsp; .collect(toList());

万千封印

我认为您也可以尝试StreamEx。它使您有机会编写更简洁,更易读的代码:StreamEx.of(animals) &nbsp;&nbsp;&nbsp;&nbsp;.flatMap(e&nbsp;->&nbsp;e.stream().map(Animal::getClass).distinct()) &nbsp;&nbsp;&nbsp;&nbsp;.distinct(2).toList();

九州编程

首先,也许您应该尝试使用flatMap而不是map。animals.stream()。map(place-> place.stream()。map(animal-> animal.getClass())。collect(Collectors.toSet()));其次,实际上我们可以使用外部ConcurrentHashMap做到这一点,这将使我们能够parallel在需要时使用。&nbsp; &nbsp; ConcurrentHashMap<Class, AtomicLong> theCounterMap = new ConcurrentHashMap<>();&nbsp; &nbsp; animals.stream().flatMap(list -> list.stream().map(animal -> animal.getClass()).distinct())&nbsp; &nbsp; &nbsp; &nbsp; .forEach(clazz -> theCounterMap.computeIfAbsent(clazz, k -> new AtomicLong()).getAndIncrement());&nbsp; &nbsp; List<Class> classList = theCounterMap.entrySet().stream()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .filter(entry -> entry.getValue().get() > 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(Map.Entry::getKey)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .collect(Collectors.toList());但是,如果您需要跟踪源列表(作为两个不同的位置),则需要进一步修改上面的解决方案。更新根据@shmosel的建议,您可以直接使用一种更简单的方法来实现相同的目标,如下所示:&nbsp; &nbsp; Map<Class, Long> theCounterMap = animals.stream().flatMap(list -> list.stream().map(animal -> animal.getClass()).distinct())&nbsp; &nbsp; &nbsp; &nbsp; .collect(Collectors.groupingBy(e -> e, Collectors.counting()));&nbsp; &nbsp; List<Class> classList = theCounterMap.entrySet().stream()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .filter(entry -> entry.getValue() > 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(Map.Entry::getKey)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .collect(Collectors.toList());
随时随地看视频慕课网APP

相关分类

Java
我要回答