可能ですか?
あなたが持っていると言う
private Set<String> names = new LinkedHashSet<String>();
とStrings
は「マイク」、「ジョン」、「カレン」です。
イテレーションなしで「John」のインデックスは何ですか?「1」を取得することは可能ですか?
以下は正常に動作します..この質問で、より良い方法があるかどうか疑問に思います
for (String s : names) {
++i;
if (s.equals(someRandomInputString)) {
break;
}
}
Set
interface には、indexOf()
メソッドのようなものはありません。あなたは本当にそれを反復するか、または代わりに indexOf()
method を提供する List
interface を使用する必要があります。
必要に応じて、Set
をList
に変換するのは簡単ですが、Set
をList
実装のコンストラクタに渡すだけで問題は解決します。例えば。
List<String> nameList = new ArrayList<String>(nameSet);
// ...
o(1) on get(index))を実現するためにarraylistに裏打ちされた挿入、削除、保持を行う実装は次のとおりです。
/**
* @Author Mo. Joseph
*
* Allows you to call get with o(1) instead of o(n) to get an instance by index
*/
public static final class $IndexLinkedHashSet<E> extends LinkedHashSet<E> {
private final ArrayList<E> list = new ArrayList<>();
public $IndexLinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}
public $IndexLinkedHashSet() {
super();
}
public $IndexLinkedHashSet(int initialCapacity) {
super(initialCapacity);
}
public $IndexLinkedHashSet(Collection<? extends E> c) {
super(c);
}
@Override
public synchronized boolean add(E e) {
if ( super.add(e) ) {
return list.add(e);
}
return false;
}
@Override
public synchronized boolean remove(Object o) {
if ( super.remove(o) ) {
return list.remove(o);
}
return false;
}
@Override
public synchronized void clear() {
super.clear();
list.clear();
}
public synchronized E get(int index) {
return list.get(index);
}
@Override
public synchronized boolean removeAll(Collection<?> c) {
if ( super.removeAll(c) ) {
return list.removeAll(c);
}
return true;
}
@Override
public synchronized boolean retainAll(Collection<?> c) {
if ( super.retainAll(c) ) {
return list.retainAll(c);
}
return false;
}
/**
* Copied from super class
*/
@Override
public synchronized boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
}
テストするには:
public static void main(String[] args) {
$IndexLinkedHashSet<String> abc = new $IndexLinkedHashSet<String>();
abc.add("8");
abc.add("8");
abc.add("8");
abc.add("2");
abc.add("3");
abc.add("4");
abc.add("1");
abc.add("5");
abc.add("8");
System.out.println("Size: " + abc.size());
int i = 0;
while ( i < abc.size()) {
System.out.println( abc.get(i) );
i++;
}
abc.remove("8");
abc.remove("5");
System.out.println("Size: " + abc.size());
i = 0;
while ( i < abc.size()) {
System.out.println( abc.get(i) );
i++;
}
abc.clear();
System.out.println("Size: " + abc.size());
i = 0;
while ( i < abc.size()) {
System.out.println( abc.get(i) );
i++;
}
}
どの出力:
Size: 6
8
2
3
4
1
5
Size: 4
2
3
4
1
Size: 0
もちろん、remove、removeAll、retainAllのパフォーマンスは、ArrayListと同じか、それより悪くなります。しかし、私はそれらを使用しないので、それで大丈夫です。
楽しい!
編集:
これは別の実装であり、冗長であるためLinkedHashSetを拡張しません。代わりに、HashSetとArrayListを使用します。
/**
* @Author Mo. Joseph
*
* Allows you to call get with o(1) instead of o(n) to get an instance by index
*/
public static final class $IndexLinkedHashSet<E> implements Set<E> {
private final ArrayList<E> list = new ArrayList<>( );
private final HashSet<E> set = new HashSet<> ( );
public synchronized boolean add(E e) {
if ( set.add(e) ) {
return list.add(e);
}
return false;
}
public synchronized boolean remove(Object o) {
if ( set.remove(o) ) {
return list.remove(o);
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return set.containsAll(c);
}
public synchronized void clear() {
set.clear();
list.clear();
}
public synchronized E get(int index) {
return list.get(index);
}
public synchronized boolean removeAll(Collection<?> c) {
if ( set.removeAll(c) ) {
return list.removeAll(c);
}
return true;
}
public synchronized boolean retainAll(Collection<?> c) {
if ( set.retainAll(c) ) {
return list.retainAll(c);
}
return false;
}
public synchronized boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
@Override
public synchronized int size() {
return set.size();
}
@Override
public synchronized boolean isEmpty() {
return set.isEmpty();
}
@Override
public synchronized boolean contains(Object o) {
return set.contains(o);
}
@Override
public synchronized Iterator<E> iterator() {
return list.iterator();
}
@Override
public synchronized Object[] toArray() {
return list.toArray();
}
@Override
public synchronized <T> T[] toArray(T[] a) {
return list.toArray(a);
}
}
これで2つの実装ができたので、2番目の実装をお勧めします。
Setが特定のSet実装に対して必ずしも適切に定義されていないため、Setがインデックスを返すことは通常不可能です。たとえば、HashSetのドキュメントに記載されています
セットの反復順序については保証されません。特に、順序が長期にわたって一定であることを保証するものではありません。
そのため、実際に期待するものがSet実装som順序であるときに、型がSetであると言ってはなりません。
信じられませんが、パフォーマンスの低下がユースケースで許容できる場合は、反復を実行するLinkedHashSetWithIndex
ラッパークラスを作成するか、各エントリのインデックスを持つ個別のテーブルを保持できます。 。
Set
は「重複する要素を含まないコレクション」であり、その要素の順序は維持されません。 http://download.Oracle.com/javase/6/docs/api/Java/util/Set.html
指定したコードが毎回1を返すとは限りません。 Set
による反復は、常に同じ順序で反復することが保証されているわけではありません。各要素を1回繰り返すことが保証されているだけです。
要素の順序を気にしているように見えるので、List
の代わりにSet
を使用する必要があります。
マシンにとっては効率的ではありませんが、これは1行でそれを実現します。
int index = new ArrayList<String>(names).indexOf("John");
コードの品質についてはわかりませんが、問題なく機能します。
セットをリストに変換してから、インデックス作成操作を実行できます。
例:セットリストを5項目にトリミングする必要があります。
Set<String> listAsLinkedHashSet = new LinkedHashSet<>();
listAsLinkedHashSet.add("1");
listAsLinkedHashSet.add("2");
listAsLinkedHashSet.add("3");
listAsLinkedHashSet.add("4");
listAsLinkedHashSet.add("1");
listAsLinkedHashSet.add("2");
listAsLinkedHashSet.add("5");
listAsLinkedHashSet.add("7");
listAsLinkedHashSet.add("9");
listAsLinkedHashSet.add("8");
listAsLinkedHashSet.add("1");
listAsLinkedHashSet.add("10");
listAsLinkedHashSet.add("11");
List<String> listAsArrayList = new ArrayList<>(listAsLinkedHashSet);
//crop list to 5 elements
if (listAsArrayList.size() > 5) {
for (int i = 5; i < listAsArrayList.size(); i++) {
listAsArrayList.remove(i);
i--;
}
}
listAsLinkedHashSet.clear();
listAsLinkedHashSet.addAll(listAsArrayList);
より良い方法はありません、単一の裏打ちされたものだけです(これは反復子も使用しますが、暗黙的に):
new ArrayList(names).get(0)