挿入順序を保持し、一意の値を持つコレクションが必要です。 LinkedHashSetは進むべき道のように見えますが、1つの問題があります。2つのアイテムが等しい場合、最新のものを削除する(これは理にかなっています)、例を次に示します。
set.add("one");
set.add("two");
set.add("three");
set.add("two");
LinkedHashSet
は次を印刷します。
one
、two
、three
しかし、私が必要なのは:
one
、three
、two
ここで最善の解決策は何でしょうか?これを行うことができるコレクション/コレクションメソッドはありますか、それを手動で実装する必要がありますか?
Java Collections のほとんどは、微調整のために拡張できます。
サブクラス 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;
}
}
単に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
を構成して、 accessは挿入だけではありません。これは多すぎるように聞こえるかもしれませんが、実際には既に含まれているキー(Set
の意味での値)の挿入にのみ影響します。影響を受ける他のMap
操作(つまりget
)は、返されるSet
では使用されません。
Java 8を使用していない場合は、型の推論が制限されているため、コンパイラを少し支援する必要があります。
Set<String> set
= Collections.newSetFromMap(new LinkedHashMap<String, Boolean>(16, 0.75f, true));
しかし、機能は同じです。
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メソッドも機能しています。
上記のソリューションはすべて優れていますが、すでに実装されているコレクションをオーバーライドしたくない場合。 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()
メソッドを呼び出す必要があることです。