2

TreeMap をキーでソートしようとしています。キーは、int、List、String などを持つカスタム DataStructure です。並べ替えを期待しているメンバーには、いくつかの重複があります。そのメンバーがランクだとしましょう。複数のオブジェクトが同じランクを持つことができます。

簡易版の例:

注: 0 未満の CompareTo メソッドでは、重複を無視しないように意図的に返されません (これが重複を回避する正しい方法でない場合は、修正してください)。

import java.util.TreeMap;


public class TreeTest {

public static void main(String[] args) {
    TreeMap<Custom,String> t = new TreeMap<Custom,String>();
    Custom c1 = new Custom();
    c1.setName("a");
    c1.setRank(0);

    Custom c2 = new Custom();
    c2.setName("b");
    c2.setRank(1);

    Custom c3 = new Custom();
    c3.setName("c");
    c3.setRank(0);

    t.put(c1, "first");
    t.put(c2, "Second");
    t.put(c3, "Third");

    System.out.println(t.keySet());

    for(Custom c:t.keySet()){
        System.out.println(t.get(c));
    }
  }
}

そしてカスタムオブジェクト

package com.example.ui;

 public class Custom implements Comparable<Custom>{

int rank;
String name;

public int getRank() {
    return rank;
}

public void setRank(int rank) {
    this.rank = rank;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}



@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + rank;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Custom other = (Custom) obj;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    if (rank != other.rank)
        return false;
    return true;
}

    // 0 is not returned intentionally to NOT ignore duplicates.
 public int compareTo(Custom o) {
    if(o.rank>this.rank)
        return 1;
    if(o.rank==this.rank)
        return -1;
    return -1;
 }
 }

出力::

[com.example.ui.Custom@fa0、com.example.ui.Custom@fbe、com.example.ui.Custom@f80]
ヌル
ヌル
ヌル

想定: ランク 0、1、0 に基づいてそれぞれ 1 位、2 位、3 位。

Googleでいくつかの例を見ました。それらのほとんどは、プリミティブ データ型のキーまたは値を使用した TreeMap 並べ替えの基本的な使用法でしたが、並べ替えメンバーがカスタム キー DataStructure の一部である場合、重複するものはありませんでした。

助けてください?

4

3 に答える 3

8

問題は、 の実装がcompareToで必要な equals と一致していないことですTreeMap。API ドキュメントから:

このソートされたマップが Map インタフェースを正しく実装するためには、(明示的なコンパレータが提供されているかどうかに関係なく) ソートされたマップによって維持される順序は equals と一致している必要があることに注意してください。

可能な一貫した実装の 1 つは、最初にランクで比較し、次にランク値が等しい場合は名前で比較することです。ランクが同じで名前が同じ Custom の 2 つのインスタンスの場合、それらの両方を同じ Map 内のキーとして格納できるとは考えないでください。これは Map の規約に違反しています。

public int compareTo(Custom o) {
  int ret = this.rank - o.rank;

  // Equal rank so fall back to comparing by name.
  if (ret == 0) {
    ret = this.name.compareTo(o.name);
  }

  return ret;
}
于 2011-09-12T08:40:23.807 に答える
0

前述のように、 equals と compareTo の実装は互いに一貫していません。あなたの質問を正しく読んだ場合、同じキーを持つ重複を保持する必要があります。Google Guava コレクションのTreeMultimapを調べることをお勧めします。同じキーを持つ異なる値が保持されるように、値オブジェクトごとにセット コンテナーを作成します。例えば

treeMultimap.put ("rank1", "Joe");
treeMultimap.put ("rank1", Jane");
treeMultimap.get ("rank1"); // Set("Joe","Jane");

このデータ構造の制約は、K,V ペアが一意でなければならないということです。つまり、Multimap に ("rank1", "Joe") を 2 回挿入することはできません。

1 つの重要な注意: 単純な型、特に文字列を使用する Map の例が非常に多く見られる理由は、マップ内のキーが不変でなければならないからです。オブジェクトの equals 値と hashcode 値は、マップでキーとして使用されている間は変更してはなりません。customObject.setRank(...)あなたの例に翻訳すると、キーとして使用されている場合、ランク値を実行して更新することはできません。そのためには、まずキーとその値を削除し、更新してから再度挿入する必要があります。

于 2011-09-12T09:11:00.940 に答える