9

Map<String, Integer>値でソートする方法を探していました。この投稿を見つけて、並べ替えの問題を解決しましたが、正確ではありませんでした。投稿によると、次のコードを書きました。

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

出力:

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

出力からわかるように、このgetメソッドは常に を返しますnull。その理由は、私のValueComparator.compare()メソッドが決して返らないためです。これは、この投稿0を作成することでわかりました。

null値の問題を解決するために、誰かがその投稿で次のことを提案しました。

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

このコードをテストしたところ、キーのマージの問題が発生しました。つまり、値が等しい場合、対応するキーがマージされます。

私も次のことを試しました:

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

どちらも機能しません。一部の値はまだnull. さらに、この回避策には論理的な問題が発生する可能性があります。

誰でも私の問題に対して完全に機能する解決策を提案できますか? 値による並べ替え機能とgetメソッドが同時に機能することを望みます。

4

4 に答える 4

6

比較関数では、値が等しい場合、キーを比較する必要があります。これにより、同じ値を持つ異なるキーが「マージ」されないことが保証されます。これは、他の方法では等しいと比較されるエントリのあいまいさが解消されるためです。

例えば:

    @Override
    public int compare(String a, String b) {
        Integer x = base.get(a);
        Integer y = base.get(b);
        if (x.equals(y)) {
            return a.compareTo(b);
        }
        return x.compareTo(y);
    }

(null 値のポリシーに一致するように上記のコードを変更する必要があります)

ただし、値でソートするアプローチは非常に脆弱であることに注意してください。「ソートされた」マップは新しいエントリの追加をサポートしていないため、かなり混乱する可能性があります。

于 2012-12-13T04:30:02.957 に答える
4
base.get(a) ==  base.get(b)

このコードは、ボックス化Integerされた s を参照によって比較します。

に変更するとbase.get(a).equals(base.get(b))、動作するはずです。

于 2012-12-13T04:03:08.650 に答える
1

これを試して ...

HashMap<String, Integer> h = new HashMap<String, Integer>();
h.put("z",30);
h.put("e",10);
h.put("b",20);
h.put("c",20);
List<Map.Entry> a = new ArrayList<Map.Entry>(h.entrySet());
Collections.sort(a,
         new Comparator() {
             public int compare(Object o1, Object o2) {
                 Map.Entry e1 = (Map.Entry) o1;
                 Map.Entry e2 = (Map.Entry) o2;
                 return ((Comparable) e1.getValue()).compareTo(e2.getValue());
             }
         });

for (Map.Entry e : a) {
        System.out.println(e.getKey() + " " + e.getValue());
}

出力:

e 10
b 20
c 20
z 30
于 2012-12-13T04:17:17.573 に答える
1

これを試して:

return base.get(a).compareTo(base.get(b));

自動ボックス化解除についてあなたが間違っていることを証明するには:

Integer a = new Integer(2);
Integer b = new Integer(2);
boolean isEqual = ( a == b );
System.out.println("equal: " + isEqual);
System.out.println("a: " + a);
System.out.println("b: " + b);

私の出力は次のとおりです。

equal: false
a: 2
b: 2
于 2012-12-13T04:17:06.477 に答える