【问题标题】:This is a very inelegant way of accomplishing what I want to accomplish. Curious what a better way is这是完成我想要完成的事情的一种非常不优雅的方式。好奇有什么更好的方法
【发布时间】:2012-09-29 04:09:51
【问题描述】:

一切正常,但看起来很糟糕。我们只需要一个包含曲棍球运动员数据的文本文件来获取数据。然后我们获取这些数据并从中创建玩家。然后列出这些球员的名单。我们从来没有给每支球队的胜利数量,所以我几乎想知道这是否是你能做的最好的。

基本上,它想要完成的是找到获胜最多的团队。这是通过计算每个球员的获胜目标,并根据他们来自哪支球队来判断的,并为该球队计算。

我通过遍历所有玩家并找到唯一的团队名称将团队列表创建为团队对象来实现这一点。

然后我浏览了球员名单,如果球员所在的球队与当前球队相同,那么他们就会为获胜进球得分。

然后,在另一个 for 循环中,找到这些目标数量最多的团队。

返回这个团队。

对于一个小任务,总共有四个 for 循环。看起来很恶心。

    /**
     * Returns the team with the most wins
     */
    public Team getTeamWithMostWins() {
        Team teamWithMostWins = new Team();
        List<Team> teams = new List<Team>();

        if (!players.isEmpty()) {

            // Compile the List of teams
            for (int i = 0; i < players.size(); i++) {
                if (!teams.contains(players.get(i).getTeam())) {
                    teams.add(new Team(players.get(i).getTeam()));
                }
            }

            // Set the wins for the teams
            for (int i = 0; i < players.size(); i++) {
                String team = players.get(i).getTeam();
                int winningGoals = players.get(i).getWinningGoals();

                // Go through the teams List to set the points
                for (int j = 0; j < teams.size(); j++) {
                    // If the current player's team is equal to the current team in the loop
                    if ((teams.get(j).getName()).equals(team)) {
                        teams.get(j).incrementWinsBy(winningGoals);
                    }
                }
            }

            int mostWins = teams.get(0).getWins();

            // Find the team with the most wins
            for (int i = 1; i < teams.size(); i++) {
                if (teams.get(i).getWins() > mostWins) {
                    teamWithMostWins = teams.get(i);
                }
            }

        }
        else {
            teamWithMostWins = null;
        }

        return teamWithMostWins;
    }

【问题讨论】:

  • 好吧,如果你只是迭代一个集合,for-each 循环通常要容易得多:)leepoint.net/notes-java/flow/loops/foreach.html 举个例子
  • 我不认为它看起来很糟糕。这是可以理解的,这远比外表或聪明更重要。

标签: java


【解决方案1】:

正如 Jordan Denison 在 cmets 中指出的那样,您可以使用 for-each 循环。请参阅下面的示例。

此外,目前您只会获得胜场数多于第一队的最后一支队伍。为了获得最多胜利的团队,您必须更新最多胜利:

int mostWins = teams.get(0).getWins();

// Find the team with the most wins
for(Team team : teams) {
    if (team.getWins() > mostWins) {
        teamWithMostWins = team;
        mostWins = team.getWins(); // <--- Update the most wins every time you find a team with more wins
    }
}

更新

此外,请考虑使用其他答案中显示的地图。

【讨论】:

    【解决方案2】:

    您可以使用地图来存储每支球队的胜利次数:

    import java.util.Map;
    import java.util.HashMap;
    
    /**
     * Returns the team with the most wins
     */
    public Team getTeamWithMostWins() {
        if (players.isEmpty()) {
            return null;
        }
    
        Map<Team, Integer> teamWins = new HashMap<String, Integer>();
    
        // Set the wins for the teams
        for (Player player : players) {
            Integer count = teamWins.get(player.getTeam());
            count = (count == null)? 0 : count;
            teamWins.set(player.getTeam(), count + player.getWinningGoals());
        }
    
        Team teamWithMostWins = null;
        Integer mostWins = 0;
    
        for (Map.Entry<Team, Integer> teamWins : map.entrySet()) {
            Team team = entry.getKey();
            Integer wins = entry.getValue();
            if (wins > mostWins) {
                mostWins = wins;
                teamWithMostWins = team;
            }
        }
    
        return teamWithMostWins;
    }
    

    为此,您必须将 hashCode() 和 equals() 方法添加到您的 Team 类中。

    【讨论】:

      【解决方案3】:

      您可以通过将其分解为具有有意义名称的较小函数来改进此代码。

      除此之外,您使用 Java 的事实有点束缚您的手脚。在对高阶函数有更好支持的语言中,这种代码可以写得非常非常简洁。

      因为您要求一个示例...这是您的代码到 Ruby 的粗略移植:

      teams = players.map(&:team).uniq
      best_team = teams.max_by { |t| players.select { |p| p.team == t }.map(&:winning_goals).reduce(0,&:+) } 
      

      【讨论】:

      • 你能给我一个最后评论的例子吗?
      • 其实没那么复杂。第一行说:“将我们的玩家列表转换为他们的团队列表。然后只保留每个唯一值中的一个。将其分配给teams。”第二行说:“找到最大化以下函数价值的团队:对于给定的团队,遍历球员列表并只保留属于该球队的球员。将得到的球员列表转换为他们的获胜目标,然后总结出来。”
      • 转换、过滤和减少列表是非常非常强大的操作。将它们与匿名函数的简洁语法结合起来,你可以用很少的代码做各种各样的事情。如果您查看 for 循环,您会发现通常您正在做这些确切的事情:转换列表,或过滤列表(可能两者兼而有之),或从列表成员中累积某种结果。但是你必须编写所有这些重复的代码来操作索引。
      【解决方案4】:
      int                  max      = 0;
      Team                 mostWins = null;
      Map< Team, Integer > counters = new HashMap<>();
      for( Player player : players )
      {
          Integer counter = counters.get( player.getTeam());
          if( counter == null ) counter = player.getWinningGoals();
          else                  counter = player.getWinningGoals() + counter
          counters.put( player.getTeam(), counter );
          if( counter > max )
          { 
              max      = counter;
              mostWins = player.getTeam();
          }
      }
      return mostWins;
      

      【讨论】:

        【解决方案5】:

        使用谷歌番石榴:

        final Multiset<Team> teamWins = HashMultiset.create();
        for (Player player : players) {
          teamWins.add(player.getTeam(), player.getWinningGoals());
        }
        
        Team teamWithMostWins =
          Collections.max(teamWins, new Comparator<Team>() {
            public int compareTo(Team team1, Team team2) {
                return teamWins.count(team1) - teamWins.count(team2);
            }
          });
        
        int mostWins = teamWins.count(teamWithMostWins);
        

        基本上,番石榴集合使计数部分对您来说更简单。没有编译这个,但它应该给你正确的想法。只需确保 Team 具有正确的 .hashCode 和 .equals 方法(或者您可以假设您不会在不同的对象实例中复制团队数据);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-04-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-15
          • 2013-07-12
          • 1970-01-01
          相关资源
          最近更新 更多