Search code examples
javajava-stream

How to change the list of objects inside the map using streams?


Got two maps

Map<String, TConfig> configMaps= new HashMap<>();
Map<String, List<Issue>> issuesMap= new HashMap<>();

@Data
public class TConfig {
  private String teamId;
  private String teamName;
}

@Data
public class Issue {
  private String issueId;
  private String teamId;
}

Both the maps using teamId as the key.

Wanted

I would like to set the teamId property inside the list of Issue objects present in the second map issuesMap from the teamId present as key in the first map configsMap.

Tried

I tried it but not failing.

configMaps.keySet().stream()
  .forEach(teamId -> issuesMap.values().stream()
       .filter(tid -> teamId.equals(tid))
       .forEach(is-> is.teamId=teamId)
   );

Questions

  1. How do I set it using the streams API instead of traditional for loops?
  2. Can someone tell me what is wrong here?

Solution

  • Mapping each team to their issues

    You can use objects as keys, as Basil suggested.

    Then Map<String, TConfig> configMaps= new HashMap<>(); is maybe not needed at all.

    @Data
    public class Team {  // renamed from TConfig
      private String teamId;
      private String teamName;
    }
    
    // given
    Map<Team, List<Issue>> issuesByTeam = new HashMap<>();
    

    Now I see two use-cases to change the values of this map:

    1. the issue-list is not mapped correctly to the team, some issues belong to foreign teams
    2. the issue-list was somehow distributed to teams, so that the issues inside the list (value) need to be updated with the related team (key)

    (1) Suppose your issue-list is not yet mapped correctly

    That map's values are each a list of issues. However, those List<Issues> may contain foreign issues - foreign because not all issues belong to the respective team from respective key. Then you can filter out the foreign issues, to get only team-related ones:

    for (final Team team : issuesByTeam.keySet()) {  // team must be final to use in lambda later
        List<Issue> unmappedIssues = issuesByTeam.get(team);  // suppose they are not correctly mapped yet
    
        // filtering
        List<Issue> issuesForTeam = unmappedIssues.stream()
            .filter(issue -> team.equals(issue.getTeamId()))  // only issues matching the team
            .collect(Collectors.toList());
    
        issuesByTeam.put(team, issuesForTeam);
    }
    

    You could also iterate over each entry using:

    for (Map.Entry<Team, List<Issue>> entry : issuesForTeam.entrySet()) {
        final Team team = entry.getKey();
        List<Issue> unmappedIssues = entry.getValue();
        // filter like above
        entry.setValue(issuesForTeam);
    }
    

    (2) assign the team from key to each issue in value's list

    for (Map.Entry<Team, List<Issue>> entry : issuesForTeam.entrySet()) {
        final Team team = entry.getKey();
        List<Issue> unassignedIssues = entry.getValue();
        // assign the team to each issue
        unassignedIssues.forEach(
            issue -> issue.setTeamId(team.getTeamId())
        );
    }
    

    Here you don't need a stream, List implements forEach method of interface Iterable directly.

    See also

    Following tutorials from Baeldung may help: