【问题标题】:Find N first elements which pass given condition: sums up to given number找到 N 个通过给定条件的第一个元素:求和给定的数字
【发布时间】:2019-02-27 08:57:52
【问题描述】:

我有Pocket 实例的列表

List<Pocket> pockets;

Pocket 类如下所示:

public class Pocket {
    String name;
    Double amount;
}

口袋列表示例:

[
    {"pocket1", 280},
    {"pocket2", 320},
    {"pocket3", 100},
    {"pocket4", 125},
    {"pocket5", 150},
    {"pocket6", 175}
]

我需要从给定的口袋列表中找到n 的第一个口袋,它们一起可以给出N(例如650)。如果最后一个口袋的amount 比需要的大,这个口袋应该分成两个口袋,结果列表应该只包含一个部分,与之前的n - 1 口袋一起给出N

例如,我需要按照源列表中的顺序列出口袋列表,其中包含650 的数量。请注意,3-rd 口袋被拆分,只有一半的 amount 在最后一个口袋中返回:

[
    {"pocket1", 280},
    {"pocket2", 320},
    {"pocket3", 50}
]

如何用Java Streams实现?

【问题讨论】:

  • 你已经在没有流的情况下完成了吗?
  • 我认为您的意思是总和为 650 的口袋列表,您尝试过什么?
  • 您的要求不清楚。你想:1)总和直到金额超过650? 2) 将 650 个第一口袋相加? 3) 找出总和为 650 的口袋组合?

标签: java lambda collections java-8 java-stream


【解决方案1】:

您可以使用flatMapStream 来执行此操作。见下例:

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

public class Lambda {

    public static void main(String[] args) {
        List<Pocket> pockets = Arrays.asList(
            new Pocket("pocket1", 280D),
            new Pocket("pocket2", 320D),
            new Pocket("pocket3", 100D),
            new Pocket("pocket4", 50D));

        System.out.println("Filtered");
        pockets.stream()
            .flatMap(new SplitFunction(651))
            .forEach(System.out::println);

        System.out.println("Original");
        pockets.forEach(System.out::println);
    }
}


class SplitFunction implements Function<Pocket, Stream<Pocket>> {

private double max;

public SplitFunction(double max) {
    this.max = max;
}

@Override
public Stream<Pocket> apply(Pocket pocket) {
    if (Double.compare(max, pocket.amount) >= 0) {
        max -= pocket.amount;
        return Stream.of(pocket);
    } else if (Double.compare(max, 0.0) > 0) {
        Pocket lastPocket = new Pocket(pocket.name, max);
        max = 0;

        return Stream.of(lastPocket);
    }
    return Stream.empty();
}
}

上面的代码打印:

Filtered
Pocket{name='pocket1', amount=280.0}
Pocket{name='pocket2', amount=320.0}
Pocket{name='pocket3', amount=51.0}
Original
Pocket{name='pocket1', amount=280.0}
Pocket{name='pocket2', amount=320.0}
Pocket{name='pocket3', amount=100.0}
Pocket{name='pocket4', amount=50.0}

【讨论】:

  • 示例运行良好但对我来说仍不清楚,@Michał Ziober 能否提供证据我可以在哪里调查解决方案?
  • @user3219730,您能否具体说明“证明”是什么意思。你的意思是我应该解释算法为什么会起作用?
  • 通过证明,我指的是带有一些描述的书籍、文章或示例的链接。我完全理解了一种算法,我只是想了解为什么在这里 pockets.stream().flatMap(new SplitFunction(651)) 创建了一个 SplitFunction 实例,而不是为流中的每个元素创建一个新实例。
  • @Kuinji43,这就是 mapper 参数的文档所说的:“映射器 - 一种无干扰、无状态的函数,适用于每个元素,产生新的值流”。这就是这种方法的实现方式。当然我们的实现不是stateless,因为我们保留amount。但是对于不是stream(),它应该可以正常工作。当您开始使用parallelStream() 时会出现一些问题,所以我不建议这样做。见JavaDoc
猜你喜欢
  • 1970-01-01
  • 2016-10-11
  • 2018-08-03
  • 1970-01-01
  • 1970-01-01
  • 2023-02-10
  • 1970-01-01
  • 2016-03-13
  • 1970-01-01
相关资源
最近更新 更多