当前位置: 首页 > 知识库问答 >
问题:

使用java stream查找最大的3家店铺

商开济
2023-03-14

我有一个商店对象列表,这些对象按其拥有的物品进行分组。

class Shop{
  String shopName;
  String item;
  int size;
...}

我怎样才能得到每个商品的3家最大商店(或n家最大商店)的列表?假设我有

Shop("Walmart", "Hammer", 100);
Shop("Target", "Scissor", 30);
Shop("Walgreens", "Hammer", 300);
Shop("Glens", "Hammer", 500);
Shop("Walmart", "Scissor", 75);
Shop("Toms", "Hammer", 150);

我想返回按商品分组的前3家商店的列表。我对项目进行了分组,但不确定如何遍历给定的映射或入口集。。。

public class Shop {
  int size;
  String item;
  String name;

  public Shop(int size, String item, String name){
    this.size = size;
    this.item = item;
    this.name = name;
  }



  //Return a list of the top 3 largest shops by item
  public static void main(){


    List<Shop> shops = new LinkedList<Shop>();


    Comparator<Shop> shopComparator = new Comparator<Shop>(){
      @Override
      public int compare(Shop f1, Shop f2) {
        return f1.getSize() < f2.getSize() ? 1 : -1;
      }
    };

    shops.stream().collect(groupingBy(Shop::getItem))
            .entrySet()
            .stream()
            .filter(entry -> entry.getValue().stream().map )
            .forEach(item -> item.getValue())//Stuck here
            ;
  }

}

共有3个答案

敖永丰
2023-03-14

虽然不像MC皇帝那样花哨,但似乎很管用。我从你已经做过的部分开始:

shops.stream().collect(Collectors.groupingBy(Shop::getItem))
        .entrySet().stream().map(entry -> {
            entry.setValue(entry.getValue().stream()
              .sorted(Comparator.comparingInt(s->-s.size))
              .limit(3) // only keep top 3
              .collect(Collectors.toList()));
            return entry;
    }).forEach(item -> {
        System.out.println(item.getKey()+":"+item.getValue());
    });
杨学真
2023-03-14

你可以采取以下步骤:

>

现在我们需要排序List

Collectors.collectingAndThen(Collectors.toList(), finisherFunction);

我们的finisher函数应该对列表进行排序:

list -> {
    Collections.sort(list, Comparator.comparing(Shop::size).reversed());
    return list;
}

这将导致映射

现在我们唯一需要做的是将列表大小限制为3。我们可以使用subList。我认为subList如果列表包含少于3项,则会抛出异常,因此我们需要使用Math.min(3,list.size())来考虑这一点。

list -> {
    Collections.sort(list, Comparator.comparing(Shop::size).reversed());
    return list.subList(0, Math.min(3, list.size()));
}

整个代码看起来像这样:

shops.stream()
    .collect(groupingBy(Shop::item, Collectors.collectingAndThen(Collectors.toList(), list -> {
        Collections.sort(list, Comparator.comparing(Shop::size).reversed());
        return list.subList(0, Math.min(3, list.size()));
    })));

在线演示

您可以创建一个小型类来自动执行此操作,而不是“手动”对列表进行排序并将其限制为3,这样可以在添加元素时对列表进行限制和排序。

严正初
2023-03-14

关于流,您可以了解到的最重要的一点是,从任何衡量标准来看,它们并不天生比同等方法“更好”。有时,它们使代码更具可读性,而有时则不那么可读。使用它们来澄清您的代码,并在它们混淆代码时避免使用它们。

在这种情况下,通过使用收集器,您的代码将更具可读性。编写自己的代码相当容易,如果你真的想更好地理解流,我推荐它作为一个简单的学习练习。

在这里,我使用的是更多的收集器。StreamEx库中的最大值()

Comparator<Shop> bySize = Comparator.comparingInt(Shop::getSize);
Map<String, List<Shop>> biggestByItem
    = shops.stream().collect(groupingBy(Shop::getItem, greatest(bySize, 3)));

这并不是因为它更短,也不是因为它更快,并且使用恒定的内存;这样做更好,因为复杂性被排除在代码之外,隐藏在解释行为的有意义的名称后面。您编写(或引用)了一个行为清晰的可重用收集器,而不是将应用程序与需要独立读取、测试和维护的复杂管道混为一谈。

正如我提到的,在理解收集器的各个部分是如何协同工作的过程中,有一个学习曲线,但它值得研究。下面是一个类似收集器的可能实现:

public static <T> Collector<T, ?, List<T>> top(int limit, Comparator<? super T> order) {
    if (limit < 1) throw new IndexOutOfBoundsException(limit);
    Objects.requireNonNull(order);

    Supplier<Queue<T>> supplier = () -> new PriorityQueue<>(order);
    BiConsumer<Queue<T>, T> accumulator = (q, e) -> collect(order, limit, q, e);
    BinaryOperator<Queue<T>> combiner = (q1, q2) -> {
        q2.forEach(e -> collect(order, limit, q1, e));
        return q1;
    };
    Function<Queue<T>, List<T>> finisher = q -> {
        List<T> list = new ArrayList<>(q);
        Collections.reverse(list);
        return list;
    };
    return Collector.of(supplier, accumulator, combiner, finisher, Collector.Characteristics.UNORDERED);
}

private static <T> void collect(Comparator<? super T> order, int limit, Queue<T> q, T e) {
    if (q.size() < limit) {
        q.add(e);
    } else if (order.compare(e, q.peek()) > 0) {
        q.remove();
        q.add(e);
    }
}

考虑到这个工厂,创建其他工厂给您提供底部(3,按大小)等等是很简单的。

你可能对这个相关问题及其答案感兴趣。

 类似资料:
  • 问题内容: 对于需要解决的问题之一,我使用for循环找到了数组的最大值,因此我尝试使用递归找到它,这就是我想出的: 因此它可以正常工作并获取最大值,但是我的问题是:对于基本情况,返回a [head]以及对于在开头处的值大于最后一个值的情况,可以吗? 问题答案: 您只需一个计数器即可轻松完成此操作,只需使用您这次想要比较的值的索引即可: 这样可以更好地显示正在发生的情况,并使用默认的“递归”布局,例

  • 作为这个问题的一部分,我需要找到: 数字的数量(计数) 数字之和(sum) 数字的平均值(平均值) 哪些数字是偶数(偶数) 哪些数字是奇数(赔率) 我尝试在while循环中执行此操作: 其思想是,当while循环迭代时,它会将它通过的数字与最大值进行比较,并将它在计数中找到的最大值与最大值进行匹配,如果它找到的数字大于最大值,则成为新的最大值。对最小的也是同样的想法。 但它并不起作用。我该怎么办?

  • 我有m行,其中x和y值用空格分隔,表示用户id。这就像用户x在Facebook或Instagram上跟踪用户y一样。现在如果我们有一对z和y,那么由于z跟踪y,因为我们已经有一个组[x,y],那么我们可以合并z形成[x,y,z] 例: 我们可以有以下组: [1 2 5 6]和[3 4],最大组[1,2,5,6]的长度为4将是答案。 这是我对此的方法: 我的方法本身是错误的,因为我生成的列表没有正确

  • 我一直在想方设法找出解决这个问题的最好办法。 我有一个包含3列的电子表格。 列是日期(每月明细) 列包括时间(每小时细分) 列包含特定日期该小时内发生的事件计数 我想做的是找出事件发生的最常见时间。所以我并不需要日期,我只是想知道一天中最有可能发生事件的时间,这样我就可以从最好的时间到最坏的时间排序。 因此,我知道我需要以某种方式将与不同日期相匹配的小时数,以及它们的事件总数结合起来,但我不知道如

  • 问题内容: 我想找到列的2nd,3rd,… nth个最大值。 问题答案: 您可以将列排序为降序格式,然后仅从第n行获取值。 编辑:: 根据评论请求进行了更新。 警告 完全未经测试! 类似于上面的内容对于Oracle应该适用…您可能必须首先正确使用语法!

  • 本文向大家介绍JavaScript 查找最小或最大元素,包括了JavaScript 查找最小或最大元素的使用技巧和注意事项,需要的朋友参考一下 示例 如果您的数组或类似数组的对象是numeric,也就是说,如果它的所有元素都是数字,则可以使用Math.min.apply或作为第一个参数Math.max.apply传递null,而将数组作为第二个参数传递。 6 在ES6中,可以使用...运算符扩展数