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

使用流API处理嵌套映射

谭云瀚
2023-03-14

我当前使用Streams API和forEach循环的方法:

public Map<String, Client> clientsWithMostPurchasesInEachCategory(Map<Client, Map<Product,Integer>> shopping) {

    Map<String, Client> result = new HashMap<>();

    Map<Client, Map<String, BigDecimal>> temp =
            shopping.entrySet()
                    .stream()
                    .collect(Collectors.groupingBy(Map.Entry::getKey,
                             Collectors.flatMapping(e -> e.getValue().entrySet().stream(),
                             Collectors.groupingBy(e -> e.getKey().getCategory(),
                             Collectors.mapping(ee -> ee.getKey().getPrice().multiply(BigDecimal.valueOf(ee.getValue())),
                             Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))));

    /*curious, how could I refactor that piece of code, so the method uses only one stream chain? */
    temp.forEach((client, value) 
        -> value.forEach((category, value1) 
        -> {
               if (!result.containsKey(category) ||
                   temp.get(result.get(category)).get(category).compareTo(value1) < 0)
                   result.put(category, client);
           }));    

    return result;

}

正如该方法的名称所暗示的,我希望找到一个mapmap ,其中包含每个产品类别中指定类别(作为键)中最多购买(作为值)的客户机

购物基本上是一个地图:map > map

    null

共有1个答案

包修贤
2023-03-14

你被客户分组的那一刻就注定了你的命运。顶级集合器.groupingby必须使用类别作为分组依据键。

为此,您需要在收集之前flatmap,这样您就得到了一个由client+category+spend元素组成的平面流。

这里有一个方法。我将首先为扁平流的元素定义一个POJO:

  static class ClientCategorySpend
  {
      private final Client client;
      private final String category;
      private final BigDecimal spend;

      public ClientCategorySpend(Client client, String category, BigDecimal spend)
      {
          this.client = client;
          this.category = category;
          this.spend = spend;
      }

      public String getCategory()
      {
          return category;
      }

      public Client getClient()
      {
          return client;
      }

      public BigDecimal getSpend()
      {
          return spend;
      }
  }

现在的函数是:

public static Map<String, Client> clientsWithMostPurchasesInEachCategory(Map<Client, Map<Product, Integer>> shopping)
{
     // <1>
     Collector<? super ClientCategorySpend, ?, BigDecimal> sumOfSpendByClient = Collectors.mapping(ClientCategorySpend::getSpend,
             Collectors.reducing(BigDecimal.ZERO, BigDecimal::add));


     // <2>
     Collector<? super ClientCategorySpend, ?, Map<Client, BigDecimal>> clientSpendByCategory = Collectors.groupingBy(
             ClientCategorySpend::getClient,
             sumOfSpendByClient
     );

     // <3>
     Collector<? super ClientCategorySpend, ?, Client> maxSpendingClientByCategory = Collectors.collectingAndThen(
             clientSpendByCategory,
             map -> map.entrySet().stream()
                     .max(Comparator.comparing(Map.Entry::getValue))
                     .map(Map.Entry::getKey).get()
     );

     return shopping.entrySet().stream()
            // <4>
             .flatMap(
                     entry -> entry.getValue().entrySet().stream().map(
                             entry2 -> new ClientCategorySpend(entry.getKey(),
                                     entry2.getKey().category,
                                     entry2.getKey().price.multiply(BigDecimal.valueOf(entry2.getValue())))
                     )
             ).collect(Collectors.groupingBy(ClientCategorySpend::getCategory, maxSpendingClientByCategory));
}

一旦我有了clientcategoryspens(4)的流,我就按类别对其进行分组。我使用ClientSpendByCategory收集器(2)在客户端和类别中的总支出之间创建一个映射。这又取决于sumToSpendByClient(1),它基本上是一个将花费相加的减速器。然后,您可以按照您的建议使用collectingandthen,使用max将每个map 简化为单个客户端。

 类似资料:
  • 我试图动态解析一些JSON到一个Map 但是当我尝试使用一些更复杂的JSON和嵌套信息时失败了。我试图从json解析示例数据。组织 我得到以下错误 异常在线程"main"com.fasterxml.jackson.databind.JsonMapping异常:不能反序列化实例的java.lang.字符串START_OBJECT令牌 有没有办法将复杂的JSON数据解析成映射?

  • 我如何在下面的场景中使用Mapstruct进行bean映射。 现在我想把sourceId映射到targetId,courseName映射到subjectName,studentName映射到memberName(list到list)。

  • 我用的是Protobuf 3。从文档来看,似乎无法定义嵌套贴图: 我正在尝试创建一种消息类型来表示期权链的定价信息(出价和要价)。对于那些不熟悉这些金融工具的人,基本上我有一套“到期日期(YYYYMMDD)”。在每个过期日期中,我都有一组“strikes(float number;如果需要,可以用字符串表示,我同意)”。在每次行使中,我有两个期权,一个“看跌”和一个“看涨”(这被称为期权的“右”)

  • 我尝试使用MapStruct编写映射器类,如下所示: 目前它显示了“未知属性”“customer.customerid”和“usertypes.usertype.userid”等错误。有人能帮我用MapStruct映射所有这些元素吗? 问题2:我们如何绘制跟踪图?1)customerId usertypes->user->userid 2)pdtPrice offers->OffersType->

  • 我用下面的方法尝试了嵌套映射。 我在声明“root_cause”时出错:[{“type”:“mapper_parsing_exception”,“reason”:“root映射定义有不支持的参数:[type:nested]。” 感谢您的帮助。

  • 我尝试在两个列表上循环,过滤嵌套列表,并使用java8特性将结果写回主对象。 因此,到目前为止,位置内部的子列表不会更改,这是显而易见的,因为流和收集确实会创建一个新列表,该列表不会写回位置对象中。所以我的问题是,如果有一种方法可以调用位置对象的setSubList(...)方法并将新列表写入其中。 感谢