【问题标题】:JAVA: Partitioning list of user objects on a condition using Stream API and convert to Map<String,String>JAVA:使用 Stream API 对条件下的用户对象列表进行分区并转换为 Map<String,String>
【发布时间】:2021-06-11 05:50:11
【问题描述】:

我有一个类 Agent,它有以下成员:

class Agent{ 
   String name;
   long funds;
   //... getters and setters, parameterized constructor
}

现在,我有一个 Agent 类对象的列表。

ArrayList<Agent> listAgents=new ArrayList<Agent>();

我想给表现最好的人打星,比如资金超过 100000 的人给 5 星,资金超过 80000 的人给 4 星,等等。

我想将此记录存储在 Map 中,例如

我尝试了以下代码:

Map<String,String> star=listAgents
    .stream()
    .collect(Collectors.groupingBy(agn->giveStars(agn.getGeneratedFund())));

这里的 giveStars 函数定义如下:

public static String giveStars(long generatedFund) {
        if(generatedFund>=100000)
            return "*****";
        else if(generatedFund<100000&& generatedFund>=80000)
            return "****";
        else if(generatedFund<80000 && generatedFund>=60000)
            return "***";
        return "";
}

这不起作用。另外,我认为这不是正确的方法。 如何使用 Stream API 的函数来做到这一点? 任何帮助,将不胜感激。提前致谢。

【问题讨论】:

  • 你给 5 颗星只要 100K+ 所以它总是首先返回,4 星的条件永远不会正确(相同的数字小于 100K 和超过 800K),所以 1M+ 应该给 5 颗星。大数最好用下划线隔开:1_000_000800_000
  • @Alex Rudenko 感谢您的回复以及您对下划线概念的建议。这些数字仅用于演示。对困惑感到抱歉。实际上,该 group by 并没有给出预期的结果。

标签: java collections java-stream collectors


【解决方案1】:

首先,方法giveStars有问题,应该重写:

public static String giveStars(long generatedFund) {
    if (generatedFund >= 1_000_000)
        return "*****";
    else if (generatedFund >=800_000)
        return "****";
    else if (generatedFund >= 600_000)
        return "***";
    return "";
}

接下来,代码Collectors.groupingBy(agn-&gt;giveStars(agn.getGeneratedFund())) 与创建地图Map&lt;String, String&gt; 的意图相矛盾——它将创建Map&lt;String, List&lt;Agent&gt;&gt;,其中关键是星级。所以也许你真正的意图是改变地图的类型。

Map<String, List<Agent>> groupByStars = listAgents.stream()
        .collect(Collectors.groupingBy(agent -> giveStars(agent.getGeneratedFund())));

这样的地图将让我们立即获得顶级代理。

如果需要Map&lt;String, String&gt;(代理名称到星级评分),则可以按照前面的建议使用toMap 收集器,但这仅在代理名称唯一的情况下才有效。如果可能出现某些重复值,则需要使用合并功能(例如,让代理获得更好的评分):

Map<String, String> groupByAgentName = listAgents.stream()
        .collect(Collectors.toMap(
            Agent::getName, 
            agent -> giveStars(agent.getGeneratedFund()),
            (rating1, rating2) -> rating1.length() > rating2.length() ? rating1 : rating2,
            LinkedHashMap::new // keep insertion order
        ));

【讨论】:

  • 我重写了 giveStars 函数。我希望最终输出为 Map。我为此尝试了您的方法。但这会导致错误“类型不匹配:无法从 Map 转换为 Map
  • 错误清楚地表明giveStars在您更改giveStars函数后返回Object而不是String(因此接受的答案与您在评论中提到的“问题”相同)
【解决方案2】:

假设 意味着您有一个代理名称到其星级的映射,您不想分组,您想将现有项目映射到不同的那些。

这是一种方法:

Map<String,String> star = listAgents.stream()
   .collect(Collectors.toMap(Agent::getName, agn->giveStars(agn.getGeneratedFund())));

如果您对项目进行分组,则不会更改它们,而是分配给不同的组 (doh)。映射是一个将对象更改为不同对象的过程。

【讨论】:

  • 我收到此错误:类型不匹配:无法从 Map 转换为 HashMap
  • @Yash 您正在使用其他代码,那么您的问题是什么?问题中没有 HashMap,你有 Map 那里
  • 对不起,我使用了 HashMap。我将其更改为 Map。非常感谢您的回答。
猜你喜欢
  • 2021-11-17
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-31
相关资源
最近更新 更多