【问题标题】:Java 8 Stream/Collectors grouping by with MapsJava 8 Stream/Collectors 使用 Maps 分组
【发布时间】:2018-02-27 05:27:13
【问题描述】:

我有两张地图

  1. scoreMap<String,Float> 有一个组名作为键,它的 得分为价值
  2. thresholdMap<Float,String> 有一个阈值 作为价值的关键和相关评论。
  3. 我需要想出 Map&lt;String,List&lt;String&gt;&gt; 从这里。读为Map<comment,List of groups its applicable to>Map&lt;group, comment&gt; 也可以。

逻辑很简单,就是从scoresMap中取出score,和threshold Map中的threshold比较。根据它落在哪里(即高于高、介于高和中或低于中,从thresholdMap 中选择相关评论。

大概是这样的:

BiFunction<Map<String,Float>, Map<Float,String>, Map<String,String>> or
BiFunction<Map<String,Float>, Map<Float,String>, Map<String,List<String>>>

我还没有弄清楚如何使用检查 3 个条件的 Predicate 来执行 groupingBy,因此对于没有其他示例 Stream 代码表示歉意!非流代码看起来像这样(不使用地图):

if(orgScorePct >= HI_THRESHOLD) 
    return "ORG_HI_SCORE_COMMENT";
if(orgScorePct < HI_THRESHOLD && orgScorePct > MED_THRESHOLD) 
    return "ORG_MED_SCORE_COMMENT";
return "ORG_LOW_SCORE_COMMENT";

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    首先,使用TreeMap 作为阈值会容易得多:由于它是键上的排序映射,因此确定给定值的正确阈值注释只需获取floorEntry 表示该值。天花板条目对应于在给定键下方具有键的条目。类似地,ceilingEntry 可以检索具有紧跟给定键之后的键的条目。

    考虑到这一点,我们可以得到以下内容(带有示例数据):

    Map<String,Float> scoreMap = new HashMap<>();
    TreeMap<Float,String> thresholdMap = new TreeMap<>();
    
    scoreMap.put("name1", 1.0f);
    scoreMap.put("name2", 2.0f);
    scoreMap.put("name3", 3.0f);
    scoreMap.put("name4", 5.0f);
    
    thresholdMap.put(0.5f, "comment0");
    thresholdMap.put(1.5f, "comment1");
    thresholdMap.put(4.5f, "comment2");
    
    Map<String,List<String>> result =
        scoreMap.entrySet()
                .stream()
                .collect(Collectors.groupingBy(
                    e -> thresholdMap.floorEntry(e.getValue()).getValue(),
                    Collectors.mapping(Map.Entry::getKey, Collectors.toList())
                ));
    

    这导致{comment2=[name4], comment1=[name3, name2], comment0=[name1]} 是正确的:"comment2" 的阈值是 4.5,并且只有 "name4" 的分数高于该值; "comment1" 的阈值为 1.5,"name2""name3" 的得分都在 1.5 和 4.5 之间,等等。

    如果没有楼层条目要小心:可能是分数没有相应的阈值;例如,在上面的数据中,0 分会导致问题。要处理这种情况,您需要检查 floorEntry 是否返回 null 并通过返回默认值进行相应处理。

    【讨论】:

    • 感谢@Tunaki 的出色回答,我想我也会写下我想到的另一个选项,以便为其他需要它的人获取 MapBiFunction&lt;Map&lt;String,Float&gt;, TreeMap&lt;Float, String&gt;, Map&lt;String,String&gt;&gt; buildGroupComments2 = (A, B) -&gt; A.entrySet().stream().collect(Collectors.toMap( e-&gt;e.getKey(), e-&gt;B.floorEntry(e.getValue()).getValue()));
    【解决方案2】:
        List<BeanClass> list1 = new ArrayList<BeanClass>();
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        list1.add(new BeanClass(123,abc,99.0,formatter.parse("2018-02-01")));
        list1.add(new BeanClass(456,xyz,99.0,formatter.parse("2014-01-01")));
        list1.add(new BeanClass(789,pqr,95.0,formatter.parse("2014-01-01")));
        list1.add(new BeanClass(1011,def,99.0,formatter.parse("2014-01-01")));
        Map<Object, Optional<Double>> byDate = list1.stream()
       .collect(Collectors.groupingBy(p -> formatter.format(p.getCurrentDate()),
        Collectors.mapping(BeanClass::getAmount, Collectors.maxBy(Double::compare))));
    

    【讨论】:

    • 虽然此代码可以回答问题,但提供有关它如何解决问题的附加说明将提高答案的长期价值。
    猜你喜欢
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 2019-12-06
    • 1970-01-01
    • 2014-08-14
    相关资源
    最近更新 更多