【问题标题】:Collect complex objects in one lambda expression在一个 lambda 表达式中收集复杂对象
【发布时间】:2019-09-24 05:10:21
【问题描述】:

我有一个对象列表。首先,我需要按类型对其进行排序。 比面值。最后,总结所有数量:

      class Coin{
            String type;
            BigInteger faceValue;
            BigInteger quantity;
...
       }

            List<Coin> coins = new ArrayList<>();
            coins.add(new Coin("USD", 1, 150));
            coins.add(new Coin("USD", 1, 6));
            coins.add(new Coin("USD", 1, 60));
            coins.add(new Coin("USD", 2, 100));
            coins.add(new Coin("USD", 2, 100));
            coins.add(new Coin("CAD", 1, 111));
            coins.add(new Coin("CAD", 1, 222));

结果列表必须只包含 3 个新硬币对象:

Coin("USD", 1 , 216)
Coin("USD", 2 , 200)
Coin("CAD", 1 , 333)

这怎么能只写在一个 lambda 表达式中?

【问题讨论】:

  • 当你说“一个 lambda 表达式”时,你真的是指一个 lambda 表达式,还是一个可能包含 多个 lambda(和方法引用等)的调用链.)?
  • 您是否需要坚持这种设计(恕我直言,这根本不是最佳的),或者您可以根据需要更改课程设计吗?
  • 是的,它可能包含多个 lambdas

标签: java lambda java-stream grouping


【解决方案1】:

您可以使用Collectors.toMap 解决这个问题:

public List<Coin> groupedCoins(List<Coin> coins) {
    return new ArrayList<>(
            coins.stream()
                    .collect(Collectors.toMap(
                            coin -> Arrays.asList(coin.getType(), coin.getFaceValue()), Function.identity(),
                            (coin1, coin2) -> {
                                BigInteger netQ = coin1.getQuantity().add(coin2.getQuantity());
                                return new Coin(coin1.getType(), coin1.getFaceValue(), netQ);
                            }))
                    .values());
}

或者更复杂的单列分组和总和为:

public List<Coin> groupedAndSummedCoins(List<Coin> coins) {
    return coins.stream()
            .collect(Collectors.groupingBy(Coin::getType,
                    Collectors.groupingBy(Coin::getFaceValue,
                            Collectors.reducing(BigInteger.ZERO, Coin::getQuantity, BigInteger::add))))
            .entrySet()
            .stream()
            .flatMap(e -> e.getValue().entrySet().stream()
                    .map(a -> new Coin(e.getKey(), a.getKey(), a.getValue())))
            .collect(Collectors.toList());
}

【讨论】:

  • 为什么人们在按多个值分组时首先想到的是使用可能模棱两可、效率低下的字符串?您可以简单地使用coin -&gt; Arrays.asList(coin.getType(), coin.getFaceValue()),而不是coin -&gt; String.format("%s-%s", coin.getType(), coin.getFaceValue())
  • Tnx!这就是我需要的!
  • @Holger 我承认我已经看到很多人都在使用它,并且在其他地方也从您那里阅读了类似的代码建议,但是使用单个键的命名空间是自然而然的。我知道这些可能是模棱两可的,并会在未来的用例中尽量避免这种情况。谢谢提醒。 :)
  • 除了可能产生歧义之外,连接需要将每个对象转换为字符串,然后进行字符串连接操作,每个操作都可能很昂贵,那么字符串比较也不便宜.相比之下,List 只保留对原始对象的引用,并为一系列对象实现足够的hashCodeequals。字符串方法可能很诱人,因为它看起来很简单并且隐藏了所有相关成本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
相关资源
最近更新 更多