【问题标题】:Ranking list of athletes in a ascended order [closed]运动员排名升序[关闭]
【发布时间】:2021-10-18 00:34:51
【问题描述】:

有运动员的总分。我想按总分对列表进行排序,并将位置(地点)添加到position 字段。 在相同分数的情况下,运动员必须共享名额,例如3-4 和 3-4 而不是 3 和 4。

input date:
 - ABC 10, 
 - BBC 8, 
 - CBC 11,
 - ACD 8

expected output:
 pos,  name, score
- 1,   CBC,  11
- 2,   ABC,  10
- 3-4, BBC,  8
- 3-4, ACD,  8

我的解决方案看起来有点复杂,有没有更好的方法?

class Athlete {
   private String name;
   private Long totalScore;
   private String position;
}

List<Athlete> athletes = new ArrayList()<>;
...
        int i = 0;
        int rank = 0;
        long score = Integer.MIN_VALUE;
        Map<Integer, Integer> rankings = new HashMap<>();
        for (Athlete athlete : athletes) {
            ++i;
            if (score != athlete.getTotalScore()) {
                rank = i;
                rankings.put(rank, 1);
            } else {
                rankings.put(rank, rankings.get(rank) + 1);
            }
            athlete.setRank(rank + "");
            score = athlete.getTotalScore();
        }
        rankings.entrySet()
                .stream().filter(entry -> entry.getValue() > 1)
                .forEach(entry -> {
                    int pos = entry.getKey() - 1;
                    String cRank = entry.getKey() + "-" + (pos + entry.getValue());
                    IntStream.range(pos, pos + entry.getValue())
                            .forEach(p -> athletes.get(p).setRank(cRank));
                });

什么

【问题讨论】:

  • 您的解决方案真的有效吗?如果是这样,您对解决方案的特别关注是什么?如果解决方案有效,那么这可能不是您的问题的最佳位置,因为它可能更适合Stack Exchange Code Review 站点。请注意,我说“可能”会更好,因为他们对哪些问题最合适有自己的规则和规定,检查他们的help 链接是明智的。
  • @HovercraftFullOfEels 是的,它有效。我不是要改进我的解决方案。我想知道是否还有其他更好的解决方案。

标签: java algorithm sorting


【解决方案1】:

我不确定您是否需要使用流,但以下内容相当简单:

List<Athlete> athletes = Arrays.asList(new Athlete("ABC", 10), new Athlete("BBC", 8),
                                       new Athlete("CBC", 11), new Athlete("ACD", 8));

Collections.sort(athletes, Comparator.comparing(Athlete::getScore).reversed());

for(int j = 0, i = 1; i <= athletes.size(); i++)
{
    if(i == athletes.size() || athletes.get(i).getScore() != athletes.get(j).getScore())
    {
        String pos = (j + 1) + ((j + 1 == i) ? "" : "-" + i);
        while (j < i) athletes.get(j++).setPosition(pos);
    }               
}


for(Athlete a : athletes) System.out.println(a);

输出:

1 : CBC : 11
2 : ABC : 10
3-4 : BBC : 8
3-4 : ACD : 8

【讨论】:

    【解决方案2】:

    我不能说这是否更好,但它确实有效。

    List<Athlete> athletes = List.of(
            new Athlete("ABC", 10),
            new Athlete("BBC", 8),
            new Athlete("CBC", 11),
            new Athlete("ACD", 7),
            new Athlete("CCD", 7),
            new Athlete("DCD", 7),
            new Athlete("ECD", 5),
            new Athlete("FCD", 2));
    
    • 首先,将运动员的得分倒序排列。
    • 然后将具有相同总数的运动员分组到一个列表中,并以该总数为关键字。
    • 使用 LinkedHashMap 保留排序顺序。
    Map<Long, List<Athlete>> map = athletes.stream()
            .sorted(Comparator
                    .comparingLong(Athlete::getTotalScore).reversed())
            .collect(Collectors.groupingBy(Athlete::getTotalScore,
                    LinkedHashMap::new, Collectors.toList()));
    
    • 现在,遍历运动员列表中的值。
    • 如果列表的大小是单个条目,则分配当前位置。
    • 否则为列表中的每个运动员分配一个范围,从当前位置到列表大小减 1。
    int pos = 1;
    
    int pos = 1;
    for(List<Athlete> list : map.values()) {
        int size = list.size();
        for(Athlete ath :list) {
           ath.setPosition(size == 1 ? (pos+"") : (pos + "-" + (size + pos-1)));
        }
        pos += size;
    }
    
    map.values().stream().flatMap(List::stream)
            .forEach(System.out::println);
            
    

    打印

    1 CBC 11
    2 ABC 10
    3 BBC 8
    4-6 ACD 7
    4-6 CCD 7
    4-6 DCD 7
    7 ECD 5
    8 FCD 2
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多