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

如何使用流API从列表中提取3个值最高的对象

高峻
2023-03-14

我有这样一种方法:

public String mostExpensiveItems() {
        List<Entry> myList = getList();
        List<Double> expensive = myList.stream()
                .map(Entry::getAmount)
                .sorted(Comparator.reverseOrder())
                .limit(3)
                .toList();

        return "";
    }

此方法需要以如下字符串形式返回3个最昂贵项目的产品ID:

"item1, item2, item3"

我应该只能使用流,我被困在这里了。我应该能够按值对项目进行排序,然后获得产品ID,但我似乎无法使其正常工作。

入门类

public class Entry {

    private String productId;
    private LocalDate date;
    private String state;
    private String category;
    private Double amount;

    public Entry(LocalDate orderDate, String state, String productId, String category, Double sales) {
        this.date = orderDate;
        this.productId = productId;
        this.state = state;
        this.category = category;
        this.amount = sales;
    }

    public String getProductId() {
        return productId;
    }

共有2个答案

史绍晖
2023-03-14

您不需要为此任务对所有给定数据进行排序。因为排序过于繁琐,只需获取3个最大值即可。

因为排序孔数据集将花费O(n log n)时间。同时,此任务可以在一次遍历列表中完成,只保留排序顺序中以前遇到的最大值。时间复杂度将非常接近线性时间。

要实现对流的部分排序,您可以定义一个自定义收集器(一个负责从流中累积数据的对象)。

您可以使用静态方法收集器的一个版本以内联方式创建自定义收集器。或通过创建实现收集器接口的类来实现。

定义自定义收集器时需要提供以下参数:

  • 供应商<代码>供应商

请注意,使用收集器。of()只有供应商、累加器和合路器是必需的,如果需要,可以定义其他参数。

如果我们将泛型类型参数应用于下面生成收集器的方法并将其声明为期望比较器作为参数(将在PriorityQueue的构造函数中使用,并在添加元素时使用到队列)。

自定义收集器:

public static <T> Collector<T, ?, List<T>> getMaxN(int size, Comparator<T> comparator) {
    
    return Collector.of(
        () -> new PriorityQueue<>(comparator),
        (Queue<T> queue, T next) -> tryAdd(queue, next, comparator, size),
        (Queue<T> left, Queue<T> right) -> {
            right.forEach(next -> tryAdd(left, next, comparator, size));
            return left;
        },
        (Queue<T> queue) -> queue.stream().toList(),
        Collector.Characteristics.UNORDERED);
}

public static <T> void tryAdd(Queue<T> queue, T next, Comparator<T> comparator, int size) {
    if (queue.size() == size && comparator.compare(queue.element(), next) < 0) queue.remove(); // if next value is greater than the smallest element in the queue and max size has been exceeded the smallest element needs to be removed from the queue
    if (queue.size() < size) queue.add(next);
}

流:

public static <T> String getMostExpensive(List<T> list, Function<T, String> function,
                                          Comparator<T> comparator, int limit) {
    
    return list.stream()
        .collect(getMaxN(limit, comparator))
        .stream()
        .map(function)
        .collect(Collectors.joining(", "));
}

main()-演示只需要数量作为参数的伪条目。

public static void main(String[] args) {
    List<Entry> entries =
        List.of(new Entry("item1", 2.6), new Entry("item2", 3.5), new Entry("item3", 5.7),
                new Entry("item4", 1.9), new Entry("item5", 3.2), new Entry("item6", 9.5),
                new Entry("item7", 7.2), new Entry("item8", 8.1), new Entry("item9", 7.9));

    System.out.println(getMostExpensive(entries, Entry::getProductId,
                                        Comparator.comparingDouble(Entry::getAmount), 3));
}

输出

[item9, item6, item8] // final result is not sorted PriorityQueue maintains the elements in unsorted order (sorting happens only while dequeue operation happens), if these values are requeted to be sorted it could be done by changing the finisher function
叶建柏
2023-03-14

假设产品ID在Entry中,它可以是这样的。

public String mostExpensiveItems() {
    List<Entry> myList = getList();
    List<String> expensive = myList.stream()
            .sorted(Comparator.comparing(Entry::getAmount).reversed())
            .limit(3)
            .map(Entry::getProductID)
            .toList();

    return "";
}

NB:我还没有测试出来,但这应该能够传达这个想法。

 类似资料:
  • 我有这样的课: 和类似的列表,其中填充了元素。 如何使用Java8获得的最小值和最大值?

  • 如果是的话,我们能做吗? 在这里,我想从相同的MyObject对象getTestId中添加一个属性到列表中,有一种方法可以在上面的语句中添加吗?

  • 问题内容: 我想在我的SQL查询中将结果返回为- 我有一个名为employee的表,其列名称,薪水,地址。该查询应返回employee表中的前两个最高列值。 这应该是单个查询。 问题答案: 如果最高的列是,请执行以下操作: 您将对其他任何列执行相同的操作,只需在和部分中替换列名称即可。

  • 问题内容: 我有三个mysql表,我想从中提取一些信息,这些表是: 视频-代表带有分数的视频。 标签-包含标签的全局列表。 VideoTags在视频和标签之间创建关联。 我想做的就是找到每个标签的得分最高的视频。有许多具有相同标签的视频,但是我的结果集将具有与标签相同的行数。最终目标是为每个唯一标签(标签是主题加上哈希值)提供最佳视频列表(按得分)。 我的SQL noob尝试实现此目标的方法如下:

  • 我有两个类的结构如下: 基本上,Company类有一个Person对象列表,每个Person对象都可以获得一个标记值。 如果我得到Person对象的列表,有没有一种方法可以使用Java8中的Stream来查找所有Person对象中最常见的一个标记值(如果是并列的,可能只是最常见的一个随机标记)?