2

特定の順序 (ID フィールドに基づいて昇順または降順) でソートされたメソッドに 2 つのリストが入っています。

両方のリストをツリーセットに投入して、目的の結果を達成できるようにするカスタム コンパレータの実装があります。

私の問題は、ツリーセットがロードされた後です。メソッドから単一のリストを返す必要があります。私の最初の実装は順序付けを気にしなかったので、これを行いました (複合は私の名前付き TreeSet です):

    composite.addAll(custom);
    composite.addAll(reference);    

    Iterator<MyObject> anIter = composite.iterator();
    ArrayList<MyObject> returnVal = new ArrayList<MyObject>();
    while(anIter.hasNext()) 
        returnVal.add(anIter.next());

これを実行すると、「custom」と「reference」の 2 つのリストがデフォルトの順序に戻ります。Collection の iterator() メソッド状態の Javadocs は、リストを昇順で返します。これが私の問題の原因である可能性があります。

それで...元のリストの順序を保護しながら TreeSet の内容を返す方法はありませんか? ツリーセットが頭に浮かんだのは、2 つのコレクションに対してコンパレーター インターフェイスの力を利用して、addAll() でそれらを結合し、重複を排除したかったからです。

注文を保護するための提案をいただければ幸いです。

編集*

Set<MyObject> composite = new TreeSet<MyObject>(new Comparator<MyObject>(){
        @Override
        public int compare(MyObject arg0, MyObject arg1) {
            int arg0ID = arg0.getObjID();
            int arg1ID = arg1.getObjID();                
            if(arg0ID < arg1ID) return -1;
            else if(arg0ID> arg1ID) return 1;
            else return 0;
        }           
    }); 
4

1 に答える 1

3

元のリストの順序を保護しながら TreeSet の内容を返す方法はありませんか?

いいえ、もちろん違います。TreeSetこの仕事には不適切なツールです。a を使用するポイント、セットに含まれるオブジェクトに に基づく順序付けをTreeSet適用することです。Comparator別のデータ構造を使用します — はどうLinkedHashSetですか? — 挿入順序を維持しながら重複オブジェクトを削除する場合。


あなたの発言が私の決定にどのように反論しているのかわかりません。コンパレータ インターフェイスを実行したかったので、意図的に TreeSet を選択しました。... コンパレーターを使用すると、オブジェクトのどのコンポーネントをフィルター処理するかを識別できます。その能力を失いたくない

TreeSet: "要素は、使用されるコンストラクターに応じて、自然な順序付けを使用するか、セットの作成時に提供される Comparator によって順序付けられます。" .を使用して任意の注文順序 (特に挿入注文など) を選択することはできませんTreeSet。ID を表すオブジェクト フィールドを選択するためequals()に andを使用できない場合は、decorator がおよび実装を含む で、decorate-dedup-undecorate パターンを使用します。/は順序を指定するためのものであり、同一性や同等性を指定するものではありません。hashCode()LinkedHashSetequals()hashCode()ComparatorComparable


それを放棄して、LinkedHashSet のようなものに移行する必要があることを示唆していますか?

はい、正確に。どちらかをMyObject実装し.equals().hashCode()あなたが意味すること:

class MyObject {
    // snip

    @Override
    public boolean equals(Object o) {
        // boilerplate junk here
        if (!o instanceof MyObject) return false;
        MyObject other = (MyObject) o;
        return this.getObjID() == other.getObjID();
    }

    @Override
    public int hashCode() {
        return this.getObjID();
    }

    // snip
}

そして次のように重複排除します:

List<MyObject> custom = /* snip */;
List<MyObject> reference = /* snip */;

Set<MyObject> uniques = new LinkedHashSet<>(custom.size() + reference.size());
uniques.addAll(custom);
uniques.addAll(reference);
List<MyObject> deduped = new ArrayList<>(uniques);

または、私が言及した装飾 - 重複除去 - 装飾解除パターンを使用します。デコレータ クラスは次のようになります。

class Decorator {
    private final MyObject value;

    public Decorator(MyObject value) {
        this.value = value;
    }

    public MyObject getValue() {
        return value;
    }

    @Override
    public boolean equals(Object o) {
        // boilerplate junk here
        if (!o instanceof Decorator) return false;
        Decorator other = (Decorator) o;
        return this.value.getObjID() == other.value.getObjID();
    }

    @Override
    public int hashCode() {
        return this.value.getObjID();
    }
}

おおよその使い方は次のとおりです。

List<MyObject> custom = /* snip */;
List<MyObject> reference = /* snip */;

Set<Decorator> uniques = new LinkedHashSet<>(custom.size() + reference.size());
for (MyObject m : custom) uniques.add(new Decorator(m));
for (MyObject m : reference) uniques.add(new Decorator(m));

List<MyObject> deduped = new ArrayList<>(uniques.size());
for (Decorator d : uniques) deduped.add(d.getValue());
于 2012-09-17T20:06:49.623 に答える