web-dev-qa-db-ja.com

Java.util.Setから最初のアイテムを取得する方法は?

Setインスタンスがあります:

Set<String> siteIdSet = (Set<String>) pContext.getParent().getPropertyValue(getCatalogProperties().getSitesPropertyName());

pContext.getParent().getPropertyValue()はすぐに使用できるコードであり、変更するコントロールはありません。

要求:

firstデフォルト要素を(常に)取り出したいと思いました。しかし、ArrayListのようなメソッドget(index)が見つかりませんでした。

したがって、今、私はこのようにしています。

for (Iterator<String> it = siteIdSet.iterator(); it.hasNext();) {
    siteId = it.next();
    break;
}

これを達成するための(他の)効率的な方法(短くて良い)はありますか?

44
KrishPrabakar

Oracle docs から:

その名前が示すように、このインターフェイスは数学的なset抽象化をモデル化します。

Set Theory では、「「セット」は、それ自体がオブジェクトと見なされる別個のオブジェクトのコレクションです。」 - [Wikipedia-Set]

数学的には、セット内の要素は個別化されていません。それらの唯一のアイデンティティは、セット内の存在から派生します。したがって、概念的にそのようなタスクは非論理的であるため、セットの「最初の」要素を取得しても意味がありません。

セットから「最初の」要素を取得しても意味がない場合がありますが、必要なのは、セットから1つのオブジェクトを取得することだけです(どのオブジェクトであるかは保証されません)。

for(String aSiteId: siteIdSet) {
    siteId = aSiteId;
    break;
}

これはSetの「最初の」オブジェクトを取得するために(投稿した方法よりも)少し短い方法ですが、イテレータはまだ(フードの下で)作成されているため、パフォーマンス上のメリットはありません。

27
Taylor Hx

これは最初の要素を返します

set.iterator().next();
75
Sagar Koshti

または、Java8を使用:

Object firstElement = set.stream().findFirst().get();

そして、あなたはすぐにそれで何かをすることができます:

set.stream().findFirst().ifPresent(<doStuffHere>);

または、要素が欠落している場合に代替を提供したい場合(私の例では新しいデフォルト文字列を返します):

set.stream().findFirst().orElse("Empty string");

最初の要素が欠落している場合でも、例外をスローできます。

set.stream().findFirst().orElseThrow(() -> new MyElementMissingException("Ah, blip, nothing here!"));

最初の要素を最初に取得する以外の例を提供するように促してくれたAlex Vulajに感謝します。

26
Nestor Milyaev

セットは、アイテムの一意のコレクションです。したがって、最初の要素の概念はありません。ソートされた順序でアイテムが必要な場合は、 TreeSet を使用できます。そこから TreeSet#first() を使用して最初の要素を取得できます。

8
hanish.kh

tl; dr

呼び出し TreeSet::first

要素を移動し、first()を呼び出します。

new TreeSet<String>( 
    pContext.getParent().getPropertyValue( … )   // Transfer elements from your `Set` to this new `TreeSet`, an implementation of the `SortedSet` interface. 
).first()

Setには順序がありません

他の人が言ったように、定義により Set には順序がありません。したがって、「最初の」要素を要求しても意味がありません。

Setの一部の実装には、アイテムが追加された順序などの順序があります。その非公式な注文は、 Iterator で入手できます。しかし、その順序は偶然であり、保証されていません。運がよければ、Setをサポートする実装は、実際にはSortedSetである可能性があります。

CAVEAT:順序が重要な場合、そのような動作に依存しないでください。信頼性が重要でない場合、そのような文書化されていない動作は便利です。 Setを指定した場合、他に実行可能な代替手段はありません。したがって、これを試すことは何もしないよりはましです。

Object firstElement = mySet.iterator().next();

質問に直接対処するには...いいえ、空のSetの可能性のあるケースを処理しながらイテレータから最初の要素を取得する実際の短い方法ではありません。ただし、質問のifループではなく、isEmptyに対してforテストを使用することをお勧めします。

if ( ! mySet.isEmpty() ) {
    Object firstElement = mySet.iterator().next();
)

SortedSetを使用

Setでソート順を維持する場合は、 SortedSet 実装を使用します。そのような実装には以下が含まれます。

挿入順序にLinkedHashSetを使用

必要なのは、Setに追加された順序で要素を記憶することだけである場合は、 LinkedHashSet を使用します。

ドキュメントを引用するには、このクラス…

すべてのエントリを介して実行される二重リンクリストを維持します。このリンクリストは、要素がセットに挿入された順序(挿入順序)である反復順序を定義します。

6
Basil Bourque

として、あなたはpContext.getParent().getPropertyValue return Setを述べました。 SetListに変換して、最初の要素を取得できます。次のようにコードを変更するだけです:

 Set<String> siteIdSet = (Set<String>) pContext.getParent().getPropertyValue(..);
 List<String> siteIdList=new ArrayList<>(siteIdSet);

 String firstItem=siteIdList.get(0);
3
Masudul

Setは順序付けを強制しません。質問で行ったようにHashSetに対してイテレータを使用しても、常に「最初の」要素を取得する保証はありません。

予測可能な順序付けが必要な場合は、 LinkedHashSet 実装を使用する必要があります。 LinkedHashSetを反復処理すると、挿入した順序で要素が取得されます。 getLinkedHashSetメソッドがあると、どこでも具象クラスを使用する必要があるため、イテレーターを使用する必要があります。

3
Hari Menon

要素にアクセスするには、イテレータを取得する必要があります。しかし、Iteratorは、例外的な場合を除き、特定の順序での保証は行いません。そのため、最初の要素を取得するのは確実ではありません。

2
kalakanhu

これは動作します:

Object firstElement = set.toArray()[0]; 
2
Rishi Bhardwaj

これは私が先日自分自身に出くわした難しい質問です。 Java.util.LinkedHashSetは、コンテンツのリンクリスト(デフォルトでは追加順)を維持しますが、アクセサーは提供しません。他の構造タイプは、add()remove()、およびcontains()でO(1)を提供できません。

LinkedHashSetを使用してiterator()を取得し、1つの要素を取得して破棄できます。多数の異なるセットに対して頻繁にこれを実行するときに速度やメモリをあまり気にしない場合、それはおそらくあなたの解決策です...加えて、私は少し余分に望ましい機能がありました。

最終的に、RandomAccessLinkedHashSetと呼ばれる独自のクラスを作成しました。このクラスは、ハッシュテーブル、二重にリンクされたリスト、および順序に関係のない配列を同時に維持します。 SetDequeの両方に準拠するように作成しましたが、Dequeの実装は、既に含まれているPush()要素に失敗するため、少し大ざっぱです。インターフェースの契約。 3番目の構造である配列を維持することは、あなたがしていることにまったく必要ではありませんが、セット内のrandom要素へのアクセスも許可しますどんな容量でも、実際にランダムな値を提供できます。

興味があれば、このソースを提供できます。まだSerializedではありませんが、実行時には問題なく動作します。

何らかの方法で提供されるSetのタイプを保証できない場合は、Iteratorを使用する必要があります。

2
Mumbleskates

ベクターには便利な機能がいくつかあります。

Vector<String> siteIdVector = new Vector<>(siteIdSet);
String first = siteIdVector.firstElement();
String last = siteIdVector.lastElement();

しかし、私は同意します-基本セットが注文されることが保証されていないため、これは意図しない結果をもたらす可能性があります。

0
Chris Hagn

定義による設定は順序付けられていません。

おそらく間違ったコレクションを使用しています。

0
Marcin Szymczak

Setから最初の要素を取得しても意味がありません。このような要件がある場合は、セットの代わりにArrayListを使用してください。セットは重複を許可しません。それらには個別の要素が含まれています。

0
Nishant Lakhara