【问题标题】:Sorting a HashMap, while keeping duplicates对 HashMap 进行排序,同时保留重复项
【发布时间】:2012-02-09 23:13:58
【问题描述】:

我正在尝试以两种方式对HashMap 进行排序。默认方式:按值的字母顺序,第二种方式:按数字键,数字越大在顶部。我已经四处搜索,但找不到任何关于该主题的内容,而我找到的内容不起作用。如果不可能对它们都进行排序(我希望拥有最高键的人在顶部,随着人们拥有较低的键而减少,然后按字母顺序对所有其余的人进行排序(以 0 作为键的人)。

这是我迄今为止尝试过的:

private HashMap<String, Integer> userGains = new HashMap<String, Integer>();

public void sortGains(int skill, int user) {
    userGains.put(users.get(user).getUsername(), users.get(user).getGainedExperience(skill));
    HashMap<String, Integer> map = sortHashMap(userGains);
    for (int i = 0; i < map.size(); i++) {
        Application.getTrackerOutput().getOutputArea(skill).append(users.get(user).getUsername() + " gained " + map.get(users.get(user).getUsername()) + "  experience in " + getSkillName(skill) + ".\n");
    }
}

public LinkedHashMap<String, Integer> sortHashMap(HashMap<String, Integer> passedMap) {
    List<String> mapKeys = new ArrayList<String>(passedMap.keySet());
    List<Integer> mapValues = new ArrayList<Integer>(passedMap.values());
    LinkedHashMap<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();

    Collections.sort(mapValues);
    Collections.sort(mapKeys);

    Iterator<Integer> it$ = mapValues.iterator();
    while (it$.hasNext()) {
        Object val = it$.next();
        Iterator<String> keyIt = mapKeys.iterator();
        while (keyIt.hasNext()) {
            Object key = keyIt.next();
            String comp1 = passedMap.get(key).toString();
            String comp2 = val.toString();
            if (comp1.equals(comp2)) {
                passedMap.remove(key);
                mapKeys.remove(key);
                sortedMap.put((String) key, (Integer) val);
                break;
            }
        }
    }
    return sortedMap;
}

由于您无法运行,所以这里是一个 SSCCE:

private HashMap<String, Integer> userGains = new HashMap<String, Integer>();

private Object[][] testUsers = { { "Test user", 15 }, { "Test", 25 }, { "Hello", 11 }, { "I'm a user", 21 }, { "No you're not!", 14 }, { "Yes I am!", 45 }, { "Oh, okay.  Sorry about the confusion.", 0 }, { "It's quite alright.", 0 } };

public static void main(String[] arguments) {
    new Sorting().sortGains();
}

public void sortGains() {
    for (Object[] test : testUsers) {
        userGains.put((String) test[0], (Integer) test[1]);
    }
    HashMap<String, Integer> map = sortHashMap(userGains);
    for (int i = 0; i < map.size(); i++) {
        System.out.println(testUsers[i][0] + " gained " + map.get(testUsers[i][0]) + "  experience.");
    }
}

public LinkedHashMap<String, Integer> sortHashMap(HashMap<String, Integer> passedMap) {
    List<String> mapKeys = new ArrayList<String>(passedMap.keySet());
    List<Integer> mapValues = new ArrayList<Integer>(passedMap.values());
    LinkedHashMap<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();

    Collections.sort(mapValues);
    Collections.sort(mapKeys);

    Iterator<Integer> it$ = mapValues.iterator();
    while (it$.hasNext()) {
        Object val = it$.next();
        Iterator<String> keyIt = mapKeys.iterator();
        while (keyIt.hasNext()) {
            Object key = keyIt.next();
            String comp1 = passedMap.get(key).toString();
            String comp2 = val.toString();
            if (comp1.equals(comp2)) {
                passedMap.remove(key);
                mapKeys.remove(key);
                sortedMap.put((String) key, (Integer) val);
                break;
            }
        }
    }
    return sortedMap;
}

目前程序的输出是:

Test user gained 15  experience.
Test gained 25  experience.
Hello gained 11  experience.
I'm a user gained 21  experience.
No you're not! gained 14  experience.
Yes I am! gained 45  experience.
Oh, okay.  Sorry about the confusion. gained 0  experience.
It's quite alright. gained 0  experience.

当我需要它时:

Yes I am! gained 45  experience. // start numeric sorting here, by highest key.
Test gained 25  experience.
I'm a user gained 21  experience.
Test user gained 15  experience.
No you're not! gained 14  experience.
Hello gained 11  experience.
It's quite alright. gained 0  experience. // start alphabetical sorting here, if possible.
Oh, okay.  Sorry about the confusion. gained 0  experience.

有什么见解吗?

【问题讨论】:

    标签: java sorting collections hashmap


    【解决方案1】:

    不可能对HashMap 进行排序。根据定义,HashMap 中的键是无序的。如果您想订购 Map 的键,请使用带有适当 Comparator 对象的 TreeMap。如果您想以多种方式访问​​相同的数据,您可以创建多个具有不同Comparators 的TreeMaps

    【讨论】:

    • 有没有一种方法可以对用户获得的体验进行排序?我有一个 User 超类,其中包含所有信息,然后是一个包含所有用户的 ArrayList。
    • 当然,你绝对可以排序一个ArrayList;使用Collections.sort() 并提供合适的Comparator 实现。
    • 啊,我明白了。我之前正在寻找并找到提供的方法来对HashMap 进行排序,但我想这太好了,不可能是真的。使用Collections.sort() 是否允许我保留重复项,还是在Comparator 中完成?
    • OP 的代码有效。他的代码只会误导你,因为他针对 HashMap 类型声明了一个 LinkedHashMap 实例。
    • @Aeterna:Map 中不能有重复的键。你可以有一个Map 将键映射到某种集合,所以一个键可以有多个值。这通常称为 multimap。 Apache Commons 集合库有一些不错的多地图类。
    【解决方案2】:

    您在显示值时犯了一个错误。

    HashMap<String, Integer> map = sortHashMap(userGains);
    for (int i = 0; i < map.size(); i++) {
        System.out.println(testUsers[i][0] + " gained " + map.get(testUsers[i][0]) + "  experience.");
    }
    

    您需要显示地图的值而不是原始数组的值。

    应该这样做:

    HashMap<String, Integer> map = sortHashMap(userGains);
    for (Entry<String, Integer> entry : map.entrySet()) {
        System.out.println(entry.getKey() + " gained " + entry.getValue() + "  experience.");
    }
    

    您只需颠倒顺序即可。此外,我建议声明反对 Map 而不是 HashMapLinkedHashMap 以避免自己和他人混淆。您的排序也可以通过Comparable 更简单地完成。这是一个改进:

    private Map<String, Integer> userGains = new HashMap<String, Integer>();
    
    private Object[][] testUsers = { { "Test user", 15 }, { "Test", 25 }, { "Hello", 11 }, { "I'm a user", 21 }, { "No you're not!", 14 }, { "Yes I am!", 45 }, { "Oh, okay.  Sorry about the confusion.", 0 }, { "It's quite alright.", 0 } };
    
    public static void main(String[] arguments) {
        new Sorting().sortGains();
    }
    
    public void sortGains() {
        for (Object[] test : testUsers) {
            userGains.put((String) test[0], (Integer) test[1]);
        }
    
        Map<String, Integer> map = createSortedMap(userGains);
    
        for (Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " gained " + entry.getValue() + "  experience.");
        }
    }
    
    public Map<String, Integer> createSortedMap(Map<String, Integer> passedMap) {
        List<Entry<String, Integer>> entryList = new ArrayList<Entry<String, Integer>>(passedMap.entrySet());
    
        Collections.sort(entryList, new Comparator<Entry<String, Integer>>() {
    
            @Override
            public int compare(Entry<String, Integer> e1, Entry<String, Integer> e2) {
                if (!e1.getValue().equals(e2.getValue())) {
                    return e1.getValue().compareTo(e2.getValue()) * -1; // The * -1 reverses the order.
                } else {
                    return e1.getKey().compareTo(e2.getKey());
                }
            }
        });
    
        Map<String, Integer> orderedMap = new LinkedHashMap<String, Integer>();
    
        for (Entry<String, Integer> entry : entryList) {
            orderedMap.put(entry.getKey(), entry.getValue());
        }
    
        return orderedMap;
    }
    

    【讨论】:

    • 太棒了!虽然它是倒退的,你知道我怎样才能扭转方法输出的内容吗?编辑:将Collections.sort(mapValues); 更改为Collections.sort(mapValues, Collections.reverseOrder()); 效果很好:) 再次感谢。
    • 谢谢,这比我用的那个更容易理解!
    【解决方案3】:

    This question 通过对 TreeMap 中的值进行排序来接近您想要做的事情。如果您选择投票最多的答案并修改比较器以按值排序,然后按键排序,它应该会给您想要的。

    实际上,您创建了一个具有指向 TreeMap 的字段的 Comparator(因此它可以查找值)。 TreeMap 使用这个比较器。当项目被添加到 TreeMap 时,比较器会查找值并进行比较

    • 如果a值
    • 如果值 a > 值 b,则返回 -1
    • 如果key a
    • 如果key a > key b,返回-1
    • 否则,返回 0

    从该答案复制大量代码(不检查代码是否有效,因为它只是为了想法):

    public class Main {
    
        public static void main(String[] args) {
    
            ValueComparator<String> bvc =  new ValueComparator<String>();
            TreeMap<String,Integer> sorted_map = new TreeMap<String,Integer>(bvc);
            bvc.setBase(sorted_map);
    
            // add items
            // ....
    
            System.out.println("results");
                for (String key : sorted_map.keySet()) {
                System.out.println("key/value: " + key + "/"+sorted_map.get(key));
            }
         }
    
    }
    
    class ValueComparator implements Comparator<String> {
        Map base;
    
        public setBase(Map<String,Integer> base) {
            this.base = base;
        }
    
        public int compare(String a, String b) {
            Integer value_a = base.get(a);
            Integer value_b = base.get(b);
    
            if(value_a < value_b) {
                return 1;
            }
            if(value_a>< value_b) {
                return -1;
            }
            return a.compareTo(b);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-28
      • 2018-10-05
      • 2023-04-06
      • 2017-04-28
      • 2015-02-13
      • 2012-09-26
      • 2018-06-06
      • 2021-04-13
      • 1970-01-01
      相关资源
      最近更新 更多