2
import java.util.*;

public class Sort {

    static class ValueComparator implements Comparator<String> {

        Map<String, Integer> base;

        ValueComparator(Map<String, Integer> base) {
            this.base = base;
        }

        @Override
        public int compare(String a, String b) {
            if (base.get(a) >= base.get(b)) {
                return 1;
            } else {
                return -1;
            }
        }
    }

    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        ValueComparator vc = new ValueComparator(map);
        TreeMap<String, Integer> sorted = new TreeMap<String, Integer>(vc);
        map.put("A", 1);
        map.put("B", 2);
        sorted.putAll(map);
        for (String key : sorted.keySet()) {
            System.out.println(key + " : " + sorted.get(key)); // why null values here?
        }
        System.out.println(sorted.values()); // But we do have non-null values here!
    }
}

Output:

A : null
B : null
[1, 2]
BUILD SUCCESSFUL (total time: 0 seconds)

I wonder why we get null values at the first commented line while we do have non-null values as demonstrated by the second commented line.

Edit: @null's version seems not working. I've changed my code as follows:

        public int compare(String a, String b) {
            if (a.equals(b)) return 0;
            if (base.get(a) >= base.get(b)) {
                return 1;
            } else return -1;
        }

It seems to work but I'm not sure.

Terry Li
  • 16,870
  • 30
  • 89
  • 134

3 Answers3

11

My guess is that your ValueComparator.compare() method never returns 0, indicating equality, causing the Map.get() method to not find matches.

Omaha
  • 2,262
  • 15
  • 18
2

Change your compare to in this way

public int compare(String a, String b) {
        if (base.get(a) > base.get(b)) {
            return 1;
        }else if(base.get(a) ==  base.get(b)){
            return 0;
        }
        return -1;  
    }
someone
  • 6,577
  • 7
  • 37
  • 60
  • 1
    Hmm.. Rather I would just have - `return base.get(a) - base.get(b);`. – Rohit Jain Dec 12 '12 at 15:26
  • 2
    Although it seems like an easy out, using the `a-b` idiom in comparator functions has existed all the way since the days of things like `qsort()` (and likely even longer) but it carries with it an important shortcoming: If overflow occurs, the result will be incorrect; for example, consider what happens if `base.get(a)` returns `Integer.MIN_VALUE` and `base.get(b)` is positive. – Omaha Dec 12 '12 at 15:33
  • 1
    Wait, your code has a key merging problem. Unless you're aware, try it. – Terry Li Dec 12 '12 at 15:41
  • You could just do return base.get(a).compareTo(base.get(b)); and let the Integer class handle it. – Michael Krussel Dec 12 '12 at 16:25
2

Even with your Comparator which is definitely broken the program will work if you change it as

for (Map.Entry e : sorted.entrySet()) {
    System.out.println(e.getKey() + " : " + e.getValue());
}
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275