【问题标题】:Collect items into brackets (current and all preceding groups)将项目收集到括号中(当前组和所有先前组)
【发布时间】:2018-10-16 09:22:59
【问题描述】:

(对不起,如果“括号”一词令人困惑,我是从荷兰语翻译的“税括号”中提取的)。

如何根据属性阈值将项目收集到组和每个前面的组

例子:

Loan A, duration of 6 months
Loan B, duration of 10 months
Loan C, duration of 12 months

结果为@​​987654322@:

6 -> {A, B, C}
10 -> {B, C}
12 -> {C}

目前我正在使用 LinkedHashMap 路线,然后在从流中收集项目后,遍历所有组以更新它们:

Map<Integer, List<Loan>> loansByDuration = loans.stream()
        .collect(groupingBy(Loan::getDuration, LinkedHashMap::new, toList()));

List<Loan> previousGroup = null;
for (List<Loan> currentGroup : loansByDuration.values()) {
    if (previousGroup != null) {
        currentGroup.addAll(previousGroup);
    }
    previousGroup = currentGroup;
}

所以我正在做的是地图中的每个后续列表值都将包含所有以前的贷款加上仅与相应的持续时间键相关的贷款。类似于累积小计。

这可以通过标准 API 或自定义收集器之类的东西来完成吗?

【问题讨论】:

  • addAll 在这里想要达到什么目的?你为什么不在空的初始化列表上做addAll 部分?
  • 如果你会用番石榴,有RangeMap
  • @Eugene,我确实可以使用番石榴。我会看看它,但同时随时用番石榴提供答案:)
  • @nullpointer,我不明白这将如何完成同样的事情。我正在做的是地图中的每个后续列表值都将包含所有以前的贷款加上仅与相应的持续时间键相关的贷款。就像累积小计一样。
  • @Eugene,RangeMap 被标记为 Beta/Unstable。不要认为在我的情况(企业)中使用它是一个好主意。

标签: java java-stream collectors


【解决方案1】:

对于用例,是否有必要使用Map&lt;Integer, List&lt;Loan&gt;&gt; 之类的类型?因此,每个列表将包含所有以前的贷款。这意味着会有对Loan 的冗余引用。

或者是在loans上提供视图的用例,按duration分组?
在这种情况下,我们可以使用另一种方法:使用 Stream(基于 Java 9+)查看贷款。

public class Loans {

    private final List<Loan> loans;

    public Loans(List<Loan> loans) {
        this.loans = loans.stream()
                .sorted(Comparator.comparingInt(Loan::getDuration))
                .collect(Collectors.toList());
    }

    public Stream<Loan> getUpTo(int duration) {
        return loans.stream().takeWhile(l -> l.getDuration() <= duration);
    }

}

由于我们有一个按duration 排序的List&lt;Loan&gt;,我们可以使用Stream.takeWhile 来获得某个duration 所需Loans 的Stream

这有效,例如像这样:

Loans loans = new Loans(List.of(new Loan("A", 6), new Loan("B", 10), new Loan("C", 12));
loans.getUpTo(1); // <empty>
loans.getUpTo(5); // <empty>
loans.getUpTo(6); // Loan("A", 6)
loans.getUpTo(10); // Loan("A", 6), new Loan("B", 10)
loans.getUpTo(11); // Loan("A", 6), new Loan("B", 10)
loans.getUpTo(12); // Loan("A", 6), new Loan("B", 10), Loan("C", 12)
loans.getUpTo(100); // Loan("A", 6), new Loan("B", 10), Loan("C", 12)

如果需要List&lt;Loan&gt;,我们仍然可以collect 流式元素toList()

【讨论】:

    【解决方案2】:

    我能想到的简单解决方案是这样的

    class Bucket(int limit, List<Loan> elements)
    
    List<Int> buckets = Arrays.asList(6, 10, 12); // The bucket that you want to put items into
    buckets.stream.flatMap(bucketLimit -> {
        List<Loan> loans = loans.stream()
            .filter(l -> l.getDuration() <= bucket)
            .collect(Collectors.toList());
    
        return new Bucket(bucketLimit, loans);
    })
    .collect(Collectors.toMap(Bucket::limit, Bucket::loans))
    

    这里可能有一些语法错误,但你应该可以这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      • 2018-04-28
      • 2016-07-09
      • 1970-01-01
      相关资源
      最近更新 更多