【问题标题】:Grouping objects by two fields using Java 8使用 Java 8 按两个字段对对象进行分组
【发布时间】:2019-01-17 15:57:49
【问题描述】:

我在使用 Java 8 对两个值进行分组时遇到问题。

我的主要问题是关于对两个字段进行分组,我正确分组了一个名为 getNameOfCountryOrRegion() 的字段,但现在我对 groupingBy 另一个名为 leagueDTO 的字段也很感兴趣。

Map<String, List<FullCalendarDTO>> result = countryDTOList.stream()
               .collect(Collectors.groupingBy(
                             FullCalendarDTO::getNameOfCountryOrRegion));

还有以下课程:

public class FullCalendarDTO  {
    private long id;
    private TeamDTO localTeam;
    private TeamDTO visitorTeam;
    private LocationDTO location;   
    private String leagueDTO;       
    private String timeStamp;
    private String nameOfCountryOrRegion;
}

结果将按nameOfCountryOrRegionleagueDTO 分组。

【问题讨论】:

  • 你说的和leagueDTO是什么意思?会是嵌套地图吗?你能展示一下你想要的输出应该是什么样子吗?
  • 你想得到一个键是两个字段组合的映射吗?如果是这样,那么传递给groupingBy() 的函数将必须构建并返回一个适当的对象。
  • @user7 我会感觉到groupingBy 这两个属性。可能还有其他含义吗?

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


【解决方案1】:

downstream 收集器传递给groupingBy 即可:

countryDTOList.stream()
              .collect(groupingBy(FullCalendarDTO::getNameOfCountryOrRegion,
                       groupingBy(FullCalendarDTO::getLeagueDTO)));

上面的代码 sn-p 会将您的FullCalendarDTO 对象按nameOfCountryOrRegion 分组,然后每个组将按leagueDTO 分组。

所以返回的集合看起来像Map&lt;String, Map&lt;String, List&lt;FullCalendarDTO&gt;&gt;&gt;

【讨论】:

    【解决方案2】:

    如果您要使用两个属性进行分组,您的输出将是一个Map,其中键作为用于分组的第一个属性(getNameOfCountryOrRegion),值作为Map 再次将键作为用于分组的第二个属性(getLeagueDTO),将其值作为List&lt;FullCalendarDTO&gt;,根据指定的键进行分组。

    这应该看起来像:

    Map<String, Map<String, List<FullCalendarDTO>>> result = countryDTOList.stream()
            .collect(Collectors.groupingBy(FullCalendarDTO::getNameOfCountryOrRegion,
                    Collectors.groupingBy(FullCalendarDTO::getLeagueDTO)));
    

    【讨论】:

      【解决方案3】:

      Collectors 类 groupingBy() 方法支持额外的 Collector 作为第二个参数:

      public static <T, K, A, D>    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream)
      

      上面可以写成groupBy()两个值

      Map<String, List<FullCalendarDTO>> result = countryDTOList.stream().collect(Collectors.groupingBy(FullCalendarDTO::getNameOfCountryOrRegion, Collectors.groupingBy(FullCalendarDTO::getLeagueDTO)));
      

      【讨论】:

        【解决方案4】:

        如果您正在寻找要分组到 Map of Maps 中的原始列表。 下面是代码sn-p

            List<FullCalendarDTO> arrayList = new ArrayList<FullCalendarDTO>();
            arrayList.add(new FullCalendarDTO("US","A"));
            arrayList.add(new FullCalendarDTO("EU","A"));
            arrayList.add(new FullCalendarDTO("EU","A"));
            arrayList.add(new FullCalendarDTO("US","A"));
            arrayList.add(new FullCalendarDTO("US","B"));
        
            Map<String, List<FullCalendarDTO>> result = arrayList.stream().collect(Collectors.groupingBy(FullCalendarDTO::getNameOfCountryOrRegion));
        
            HashMap<String, Map<String, List<FullCalendarDTO>>> finalOutput = new HashMap<String, Map<String, List<FullCalendarDTO>>>();
            for (Entry<String, List<FullCalendarDTO>> fullCalendarDTO : result.entrySet()) {
                Map<String, List<FullCalendarDTO>> collect = fullCalendarDTO.getValue().stream().collect(Collectors.groupingBy(FullCalendarDTO::getLeagueDTO));
                finalOutput.put(fullCalendarDTO.getKey(), collect);
            }
        
            System.out.println(finalOutput);
        

        哪些输出

        {EU={A=[EU :: A, EU :: A]}, US={A=[US :: A, US :: A], B=[US :: B]}}

        【讨论】:

        • 正确的做法是使用下游收集器。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-22
        • 2020-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多