为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

素胚勾勒不出你 2021-05-06 21:20:59
假设我有一个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]
查看完整描述

3 回答

?
繁星coding

TA贡献1797条经验 获得超4个赞

首先,对所有动物进行计数,然后选择出现多次的动物:


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


查看完整回答
反对 回复 2021-05-12
?
万千封印

TA贡献1891条经验 获得超3个赞

我认为您也可以尝试StreamEx。它使您有机会编写更简洁,更易读的代码:

StreamEx.of(animals)
    .flatMap(e -> e.stream().map(Animal::getClass).distinct())
    .distinct(2).toList();


查看完整回答
反对 回复 2021-05-12
?
九州编程

TA贡献1785条经验 获得超4个赞

首先,也许您应该尝试使用flatMap而不是map。


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


其次,实际上我们可以使用外部ConcurrentHashMap做到这一点,这将使我们能够parallel在需要时使用。


    ConcurrentHashMap<Class, AtomicLong> theCounterMap = new ConcurrentHashMap<>();

    animals.stream().flatMap(list -> list.stream().map(animal -> animal.getClass()).distinct())

        .forEach(clazz -> theCounterMap.computeIfAbsent(clazz, k -> new AtomicLong()).getAndIncrement());

    List<Class> classList = theCounterMap.entrySet().stream()

            .filter(entry -> entry.getValue().get() > 1)

            .map(Map.Entry::getKey)

            .collect(Collectors.toList());

但是,如果您需要跟踪源列表(作为两个不同的位置),则需要进一步修改上面的解决方案。


更新

根据@shmosel的建议,您可以直接使用一种更简单的方法来实现相同的目标,如下所示:


    Map<Class, Long> theCounterMap = animals.stream().flatMap(list -> list.stream().map(animal -> animal.getClass()).distinct())

        .collect(Collectors.groupingBy(e -> e, Collectors.counting()));

    List<Class> classList = theCounterMap.entrySet().stream()

            .filter(entry -> entry.getValue() > 1)

            .map(Map.Entry::getKey)

            .collect(Collectors.toList());


查看完整回答
反对 回复 2021-05-12
  • 3 回答
  • 0 关注
  • 230 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信