【问题标题】:JAVA: How do I merge objects from an arrayList based on a property value?JAVA:如何根据属性值合并来自 arrayList 的对象?
【发布时间】:2018-07-17 17:24:06
【问题描述】:

我正在使用 Spring Boot、Java 和 MySQL 构建(或学习如何构建)体育 REST API。我正在构建一种方法,该方法当前从匹配集合中获取每个匹配项,并为完整的匹配项列表返回 TeamStandingsArrayList

方法如下:

public List<TeamStanding> createStandingsTable(Match[] matches){
        List<TeamStanding> teamStandings = new ArrayList<TeamStanding>();
        for(int i = 0;i < matches.length; i++) {
            TeamStanding firstTeam = new TeamStanding();
            TeamStanding secondTeam = new TeamStanding();

            //set team ids
            firstTeam.setIdTeam(matches[i].getWcmHome());
            secondTeam.setIdTeam(matches[i].getWcmAway());


            //first team stats
            firstTeam.setTeamPlayed((long) 1);
            firstTeam.setTeamGoalsFavor(matches[i].getWcmHomeGoals());
            firstTeam.setTeamGoalsAgainst(matches[i].getWcmAwayGoals());
            firstTeam.setTeamGoalDif(firstTeam.getTeamGoalsFavor() - firstTeam.getTeamGoalsAgainst());

            //second team stats
            secondTeam.setTeamPlayed((long) 1);
            secondTeam.setTeamGoalsFavor(matches[i].getWcmAwayGoals());
            secondTeam.setTeamGoalsAgainst(matches[i].getWcmHomeGoals());
            secondTeam.setTeamGoalDif(secondTeam.getTeamGoalsFavor() - secondTeam.getTeamGoalsAgainst());

            //combined team stats

            if(firstTeam.getTeamGoalsFavor() > secondTeam.getTeamGoalsFavor()) {
                firstTeam.setTeamWins((long) 1);
                firstTeam.setTeamLoses((long) 0);
                firstTeam.setTeamDraws((long) 0);
                firstTeam.setTeamPoints((long) 3);
                secondTeam.setTeamWins((long) 0);
                secondTeam.setTeamLoses((long) 1);
                secondTeam.setTeamDraws((long) 0);
                secondTeam.setTeamPoints((long) 0);
            } else if (firstTeam.getTeamGoalsFavor() == secondTeam.getTeamGoalsFavor()) {
                firstTeam.setTeamWins((long) 0);
                firstTeam.setTeamLoses((long) 0);
                firstTeam.setTeamDraws((long) 1);
                firstTeam.setTeamPoints((long) 1);
                secondTeam.setTeamWins((long) 0);
                secondTeam.setTeamLoses((long) 0);
                secondTeam.setTeamDraws((long) 1);
                secondTeam.setTeamPoints((long) 1);
            } else {
                firstTeam.setTeamWins((long) 0);
                firstTeam.setTeamLoses((long) 1);
                firstTeam.setTeamDraws((long) 0);
                firstTeam.setTeamPoints((long) 0);
                secondTeam.setTeamWins((long) 1);
                secondTeam.setTeamLoses((long) 0);
                secondTeam.setTeamDraws((long) 0);
                secondTeam.setTeamPoints((long) 3);
            }
            teamStandings.add(firstTeam);
            teamStandings.add(secondTeam);
        }
        return teamStandings;
    }

结果是这样的:

[
    {
        "idTeam": 7,
        "teamPoints": 3,
        "teamPlayed": 1,
        "teamWins": 1,
        "teamDraws": 0,
        "teamLoses": 0,
        "teamGoalsFavor": 4,
        "teamGoalsAgainst": 1,
        "teamGoalDif": 3
    },
    {
        "idTeam": 13,
        "teamPoints": 0,
        "teamPlayed": 1,
        "teamWins": 0,
        "teamDraws": 0,
        "teamLoses": 1,
        "teamGoalsFavor": 1,
        "teamGoalsAgainst": 4,
        "teamGoalDif": -3
    },
    {
        "idTeam": 4,
        "teamPoints": 3,
        "teamPlayed": 1,
        "teamWins": 1,
        "teamDraws": 0,
        "teamLoses": 0,
        "teamGoalsFavor": 1,
        "teamGoalsAgainst": 0,
        "teamGoalDif": 1
    },
    {
        "idTeam": 7,
        "teamPoints": 0,
        "teamPlayed": 1,
        "teamWins": 0,
        "teamDraws": 0,
        "teamLoses": 1,
        "teamGoalsFavor": 0,
        "teamGoalsAgainst": 1,
        "teamGoalDif": -1
    }
]

我的问题是如何根据idTeam 合并这些对象?我试图达到的结果是在idTeam 保持不变的情况下将所有其余属性加起来。在给定的示例中,预期的是:

[
        {
            "idTeam": 7,
            "teamPoints": 3,
            "teamPlayed": 2,
            "teamWins": 1,
            "teamDraws": 0,
            "teamLoses": 1,
            "teamGoalsFavor": 4,
            "teamGoalsAgainst": 2,
            "teamGoalDif": 2
        },
        {
            "idTeam": 13,
            "teamPoints": 0,
            "teamPlayed": 1,
            "teamWins": 0,
            "teamDraws": 0,
            "teamLoses": 1,
            "teamGoalsFavor": 1,
            "teamGoalsAgainst": 4,
            "teamGoalDif": -3
        },
        {
            "idTeam": 4,
            "teamPoints": 3,
            "teamPlayed": 1,
            "teamWins": 1,
            "teamDraws": 0,
            "teamLoses": 0,
            "teamGoalsFavor": 1,
            "teamGoalsAgainst": 0,
            "teamGoalDif": 1
        }
    ]

也只是一个细节,我首先构建了TeamStandingsArrayList,现在我正在尝试合并它们,但也许我应该将它们作为循环堆叠在匹配数组中,在上述相同的方法中,但是我不确定。

【问题讨论】:

    标签: java list spring-boot for-loop spring-data-jpa


    【解决方案1】:

    遍历TeamStanding 的列表,注意团队 ID 并执行添加。您可能希望使用 Map 将团队 ID 对保存为键,并将团队本身保存为值,以便于操作。这是截图(我没有测试过,所以你可能需要稍微修改一下)。

    List<TeamStanding> list = createStandingsTable(matches);
    Map<Integer, TeamStanding> map = new HashMap<>();
    
    for (TeamStanding team: list) {
        int id = team.getIdTeam();
        if (map.containsKey(id)) {
            TeamStanding other = map.get(id);
            other.setTeamPoints(team.getTeamPoints());
            other.setTeamPlayed(team.getTeamPlayed());
            // and so on...
        } else {
            map.put(id, team);
        }
    }
    
    List<TeamStanding> merged = new ArrayList<>(map.values());
    

    如果您想直接从Match[] 创建合并的List&lt;TeamStanding&gt;,那么您必须使用相同的想法,但是,将两个迭代组合在一起可能有点复杂。然后我建议你坚持这两个独立的迭代。简洁性、可读性和可维护性优于性能——此外,性能在这里并不是真正的问题。

    【讨论】:

      【解决方案2】:

      您可以使用 HashMap。使用“idTeam”作为键,使用对象 TeamStanding 作为值。现在您可以在结果列表上进行迭代,如果您在地图中找到该对象,只需更新其字段,如果您没有找到,则插入该对象。迭代完成后,您可以调用 map.values(),它会给您一个对象集合(TeamStanding),然后您可以使用该集合创建一个新的 ArrayList。

      代码如下:

      public List<TeamStanding> mergeTeamStandingList(List<TeamStanding> teamStandingList) {
          final Map<Integer, TeamStanding> idTeamVsTeamStandingMap = new HashMap<Integer, TeamStanding>();
          teamStandingList.forEach(teamStanding -> {
              if(idTeamVsTeamStandingMap.containsKey(teamStanding.getIdTeam())) {
                  TeamStanding teamStanding1 = idTeamVsTeamStandingMap.get(teamStanding.getIdTeam());
                  teamStanding1.setTeamDraws(teamStanding1.getTeamDraws() + teamStanding.getTeamDraws());
                  //so on
              } else {
                  idTeamVsTeamStandingMap.put(teamStanding.getIdTeam(), teamStanding);
              }
          });
      
          return new ArrayList<>(idTeamVsTeamStandingMap.values());
      }
      

      【讨论】:

        【解决方案3】:

        在您的 Teamstanding 对象上创建一个合并方法。

        public TeamStanding merge(TeamStanding other) {
             this.teamPoints += other.getTeamPoints();
             this.teamPlayed += other.getTeamPlayed();
             this.teamWins += other.getTeamWins();
             this.teamDraws += other.getTeamDraws();
             this.teamGoalsFavor += other.getTeamGoalsFavor();
             this.teamLoses += other.getTeamLoses();
             this.teamGoalDif += other.getTeamGoalDif();
             return this;
        }
        

        然后使用Streams按teamId进行分组,并使用merge的方法减少常用项。

        Map<Integer, Optional<TeamStanding>> mapReduced = teamStandings
        .stream()
        .collect(groupingBy(TeamStanding::getIdTeam, Collectors.reducing(TeamStanding::merge)));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-09-08
          • 2015-08-13
          • 2015-09-23
          • 1970-01-01
          • 2018-01-15
          • 2017-09-06
          • 1970-01-01
          • 2019-03-09
          相关资源
          最近更新 更多