【问题标题】:Java print TreeMap by ordered valuesJava按有序值打印TreeMap
【发布时间】:2016-04-22 16:53:35
【问题描述】:

我正在编写一个程序,将有关足球队的数据存储在嵌套树图中。它看起来像这样:

TreeMap<[team name], TreeMap<[team wins], [opponents]>>

其中 [team name] 和 [opponents] 是字符串,而 [team wins] 是 int。 我目前的目标是按团队获胜的降序打印数据。它必须看起来像:

Liverpool: //map key
wins: <wins>  //nested map key
opponents: <opponents> 

我的想法是订购嵌套地图 entrySet() 然后迭代它,同时打印数据,但我不能这样做,因为从我读到的内容中我需要 TreeSet 并且 map.entry() 只返回 Set.I需要我的地图是 TreeMap,因为当两支球队获胜时,我需要按字母顺序打印。如果我不清楚,什么是打印 TreeMap 的好方法,按嵌套的 TreeMap 键排序?

【问题讨论】:

  • 你真的有问题吗?
  • 为了获得体面帮助的最佳机会,请创建并发布一个体面的Minimal, Complete, and Verifiable example。请阅读此重要链接以了解详细信息。
  • 在高层次上,您将使用 List 来存储对手,然后调用 Collections.sort() 对列表进行排序,然后再打印。
  • @PM77-1 我的问题是如何实现我的目标。编辑了我的帖子,希望现在更清楚了。
  • 所以目前一个团队可以有多个 [team wins] 的值,您想按这些值的总和排序吗?

标签: java sorting set treemap


【解决方案1】:

TreeMap 的 (as the documentation states) 自然地按您使用的键排序。因此,如果您想按获胜次数打印数据,则需要将获胜次数作为主键。

既然您希望您的次要排序基于团队名称,那么您希望它作为您的次要键。

因此TreeMap&lt;[wins], TreeMap&lt;[team name], [opponents]&gt;&gt; 将是正确的方法。

此外,由于对手会暗示不止一个对手,您可能希望稍微复杂一些,并在需要时将其更改为以下内容:

TreeMap&lt;[wins], TreeMap&lt;[team name], ArrayList&lt;[opponent]&gt;&gt;&gt;

希望这会为您指明正确的方向。请记住,在您的情况下,自然排序将是外部 TreeMap 的 DESCENDING 顺序,即 [wins],因此请确保您的 Comparable 的 compareTo 函数执行正确的工作。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Random;
import java.util.TreeMap;

public class SO36799415 {

    public static Random random = new Random();

    public static void main(String[] args) {
        TreeMap<Integer, TreeMap<String, ArrayList<String>>> map = new TreeMap(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return -Integer.compare(o1, o2);
            }
        });
        int teams = random.nextInt(20) + 1;
        for (int i = 0; i < teams; i++) {
            addToMap(map);
        }
        for (Integer wins : map.keySet()) {
            TreeMap<String, ArrayList<String>> tmp = map.get(wins);
            for (String team : tmp.keySet()) {
                System.out.println(team);
                System.out.println("Wins: " + wins);
                System.out.println(tmp.get(team));
                System.out.println();
            }
        }
    }

    private static void addToMap(TreeMap<Integer, TreeMap<String, ArrayList<String>>> map) {
        String name = randomName();
        int wins = random.nextInt(10);
        int opponents = random.nextInt(10) + 1;
        Team team = new Team(name);
        team.setWins(wins);
        for (int i = 0; i < opponents; i++) {
            team.addOpponent(randomName());
        }
        if (map.containsKey(wins)) {
            map.get(wins).put(name, team.opponents);
        } else {
            TreeMap<String, ArrayList<String>> tmp = new TreeMap<>();
            tmp.put(name, team.opponents);
            map.put(wins, tmp);
        }
    }

    private static String randomName() {
        StringBuffer sb = new StringBuffer();
        int len = random.nextInt(10) + 1;
        for (int i = 0; i < len; i++) {
            sb.append((char) ('a' + random.nextInt(26)));
        }
        return sb.toString();
    }

    private static class Team {
        String name;
        ArrayList<String> opponents;
        int wins;

        public Team(String name) {
            this.name = name;
            this.opponents = new ArrayList<>();
            this.wins = 0;
        }

        public boolean addOpponent(String opponent) {
            return this.opponents.add(opponent);
        }

        public void setWins(int wins) {
            this.wins = wins;
        }
    }
}

【讨论】:

  • 感谢您的回答。我也是这么想的,不幸的是,当我有一个以上获胜的团队作为输入时,这个解决方案就失败了。
  • 它没有。你在说什么?你有没有试过这个?请分享您的代码。
  • 基本的 java 映射,包括 TreeMap,必须有唯一的键。如果相同的密钥用作新条目 - 它只是覆盖它。那是我的第一次尝试,我只得到了两支球队:第一支1胜,第二支0胜。从好的方面来说,它被订购了:D
  • 我看到了你的问题。固定解决方案。你必须做一些不同的事情。你不能只是覆盖。
  • 一个更简单的代码解决方案(可能不那么混乱)是只获取我创建的这些“团队”的数组,然后使用任何稳定的排序对它们进行两次排序。一次是胜利,下一次是名字。
【解决方案2】:

我会创建一个名为 sortedKeys 的 TreeMap&lt;Integer, String&gt;,然后您遍历原始 KeyMap 的所有团队,并将它们添加到 sortedKeys,使用 wins 作为键,将 TreeMap 中的键作为值。
然后,您可以迭代 sortedKeys 以按排序顺序获取键,因此您也可以按排序顺序获得结果。

编辑:由于键不能是唯一的,另一种解决方案是使用您自己的比较器创建一个 TreeSet 对,当键相等时比较值。然后你会得到这样的东西:

TreeSet<Pair<String,Pair<Integer,String>>> sortedSet = new TreeSet(new Comparator<Pair<String,Pair<Integer,String>>>() {
    @Override
    public int compare(Pair<String,Pair<Integer,String>> a, Pair<String,Pair<Integer,String>> b) {
        int res = b.getValue().getKey() - a.getValue().getKey();
        if (res == 0) {
            return a.getKey().compareTo(b.getKey());
        } else {
            return res;
        }
    }
});
teams.forEach(new BiConsumer<String,Pair<Integer,String>>() {
    @Override
    public void accept(String k, Pair<Integer,String> v) {
        sortedSet.add(new Pair(k, v));
    }
});

顺便说一下,我稍微更改了您的初始数据结构,因为您声明团队只有一个获胜值,这意味着嵌套的 TreeMap 将始终只有一个条目,因此应该只是一对。

【讨论】:

  • 好吧,我也可以这样构建我的嵌套地图:TreeMap>。 @Sanchit 和我上面讨论的问题是,你不能让多个团队获得相同的胜利,因为 Map 键必须是唯一的。
  • @Alex 查看我的更新。不要盲目更换。先检查一下。
  • 谢谢,您的回答和 Sanchit 的结合为我的问题提供了一些启示。这看起来是一个可行的解决方案。我会看看。还要感谢这对。不使用地图是有道理的,只有一个条目。我会查找这些对。
猜你喜欢
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2021-11-08
  • 2022-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多