我有一个商店对象列表,这些对象按其拥有的物品进行分组。
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
;
}
}
虽然不像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());
});
你可以采取以下步骤:
>
现在我们需要排序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,这样可以在添加元素时对列表进行限制和排序。
关于流,您可以了解到的最重要的一点是,从任何衡量标准来看,它们并不天生比同等方法“更好”。有时,它们使代码更具可读性,而有时则不那么可读。使用它们来澄清您的代码,并在它们混淆代码时避免使用它们。
在这种情况下,通过使用收集器,您的代码将更具可读性。编写自己的代码相当容易,如果你真的想更好地理解流,我推荐它作为一个简单的学习练习。
在这里,我使用的是更多的收集器。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中,可以使用...运算符扩展数