34

挿入順序を保持し、一意の値を持つコレクションが必要です。LinkedHashSet は進むべき道のように見えますが、1 つの問題があります。2 つの項目が等しい場合、最新のものを削除します (これは理にかなっています)。以下に例を示します。

set.add("one");
set.add("two");
set.add("three");
set.add("two");

LinkedHashSet印刷されます:

onetwothree

しかし、私が必要とするのは:

onethreetwo

ここで最善の解決策は何ですか?これを行うことができるコレクション/コレクションメソッドはありますか、それとも手動で実装する必要がありますか?

4

4 に答える 4

35

ほとんどのJava コレクションは、微調整のために拡張できます。

LinkedHashSetメソッドをオーバーライドするサブクラスadd

class TweakedHashSet<T> extends LinkedHashSet<T> {

    @Override
    public boolean add(T e) {
        // Get rid of old one.
        boolean wasThere = remove(e);
        // Add it.
        super.add(e);
        // Contract is "true if this set did not already contain the specified element"
        return !wasThere;
    }

}
于 2016-04-04T10:35:11.337 に答える
20

の特別な機能を簡単に使用できますLinkedHashMap

Set<String> set = Collections.newSetFromMap(new LinkedHashMap<>(16, 0.75f, true));
set.add("one");
set.add("two");
set.add("three");
set.add("two");
System.out.println(set); // prints [one, three, two]

Oracle の JRE ではとにかくLinkedHashSetによってサポートされているLinkedHashMapため、機能的な違いはあまりありませんが、ここで使用される特別なコンストラクターは、挿入時だけでなく、アクセスLinkedHashMapごとに順序を変更するように構成します。これは多すぎるように聞こえるかもしれませんが、実際には、既に含まれているキー ( の意味での値) の挿入のみに影響します。影響を受けるその他の操作 (つまり) は、返された では使用されません。SetMapgetSet

Java 8 を使用していない場合は、型推論が制限されているため、コンパイラを少し支援する必要があります。

Set<String> set
    = Collections.newSetFromMap(new LinkedHashMap<String, Boolean>(16, 0.75f, true));

機能は同じです。

于 2016-04-04T16:04:52.643 に答える
6

LinkedHashSet を初期化するときに、add メソッドをオーバーライドできます。

Set<String> set = new LinkedHashSet<String>(){
    @Override
    public boolean add(String s) {
        if(contains(s))
            remove(s);
        return super.add(s);
    }
};

今それはあなたを与える:

set.add("1");
set.add("2");
set.add("3");
set.add("1");
set.addAll(Collections.singleton("2"));

// [3, 1 ,2]

addAll メソッドでさえ機能しています。

于 2016-04-04T10:32:44.887 に答える
1

上記のすべてのソリューションは優れていますが、既に実装されているコレクションをオーバーライドしたくない場合。ちょっとしたトリックで ArrayList を使用するだけで、この問題を解決できます。

リストにデータを挿入するために使用するメソッドを作成できます

public static <T> void addToList(List<T> list, T element) {
    list.remove(element); // Will remove element from list, if list contains it
    list.add(element); // Will add element again to the list 
}

そして、このメソッドを呼び出して要素をリストに追加できます

List<String> list = new ArrayList<>();

addToList(list, "one");
addToList(list, "two");
addToList(list, "three");
addToList(list, "two");

ここでの唯一の欠点は、addToList()代わりに毎回カスタム メソッドを呼び出す必要があることです。list.add()

于 2016-11-20T06:33:13.730 に答える