对HashMap进行排序,同时保持重复

时间:2012-01-13 19:08:04

标签: java sorting collections hashmap

我正试图以两种方式对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.

有什么见解?

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分: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.");
}

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

这应该做:

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;
}

答案 2 :(得分:1)

通过对TreeMap中的值进行排序,

This问题可以解决您尝试执行的操作。如果您采用最多投票的答案并修改比较器以对值进行排序然后键,那么它应该为您提供所需的答案。

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

上进行比较
  • 如果值a&lt;值b,返回1
  • 如果值a&gt;值b,返回-1
  • 如果密钥a&lt;键b,返回1
  • 如果密钥a&gt;键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);
    }
}