243

java.util.Set正当な理由があると確信していますが、インターフェイスに がない理由get(int Index)、または同様のget()方法を誰かが説明してもらえますか?

セットは物を入れるのに最適なようですが、そこから単一のアイテムを取得するエレガントな方法が見つかりません.

最初のアイテムが必要なことがわかっている場合は、を使用できますset.iterator().next()が、それ以外の場合は、特定のインデックスでアイテムを取得するために配列にキャストする必要があるようです?

セットからデータを取得する適切な方法は何ですか? (イテレータを使用する以外)

それがAPIから除外されているという事実は、これを行わない正当な理由があることを意味していると確信しています.誰かが私を啓発してもらえますか?

編集: ここでいくつかの非常に優れた回答と、「より多くのコンテキスト」と言っているいくつか。具体的なシナリオは dbUnit テストで、クエリから返されたセットにはアイテムが 1 つしかないことを合理的に主張でき、そのアイテムにアクセスしようとしていました。

ただし、質問はより焦点を絞ったままであるため、シナリオがなくてもより有効です。

set と list の違いは何ですか

以下の素晴らしい回答に感謝します。

4

19 に答える 19

180

セットには順序がないためです。一部の実装 (特にjava.util.SortedSetインターフェースを実装するもの) はそうしますが、それはセットの一般的なプロパティではありません。

このようにセットを使用しようとしている場合は、代わりにリストの使用を検討する必要があります。

于 2009-04-20T19:20:33.657 に答える
77

実際、これは、オブジェクトリレーショナルマッピングを使用するJavaEEアプリケーションを作成するときに繰り返し発生する質問です(たとえば、Hibernateを使用)。そして、ここに返信したすべての人々から、アンドレアス・ピーターソンは本当の問題を理解し、それに正しい答えを提供した唯一の人です:JavaにはUniqueListがありません!(または、OrderedSetまたはIndexedSetと呼ぶこともできます)。

Maxwingは、このユースケース(順序付けられた一意のデータが必要)について言及し、SortedSetを提案しましたが、これはMartyPittが実際に必要としていたものではありません。

この「IndexedSet」はSortedSetと同じではありません。SortedSetでは、要素はコンパレータを使用して(または「自然な」順序を使用して)並べ替えられます。

ただし、代わりに、LinkedHashSet(他の人も提案)に近いか、(存在しない) "ArrayListSet"にさらに近いです。これは、要素が挿入されたのと同じ順序で返されることが保証されるためです。

ただし、LinkedHashSetは実装であり、インターフェイスではありません。必要なのは、IndexedSet(またはListSet、OrderedSet、UniqueList)インターフェイスです。これにより、プログラマーは、特定の順序を持​​ち、重複のない要素のコレクションが必要であることを指定し、それを任意の実装(たとえば、Hibernateによって提供される実装)でインスタンス化できます。

JDKはオープンソースであるため、このインターフェイスは最終的にJava7に含まれる可能性があります...

于 2010-05-30T00:55:09.507 に答える
29

mmyersの回答で言及されていない1つのポイントを追加するだけです。

最初のアイテムが必要であることがわかっている場合は、set.iterator()。next()を使用できますが、それ以外の場合は、特定のインデックスでアイテムを取得するために配列にキャストする必要があるようです。

セットからデータを取得する適切な方法は何ですか?(イテレータを使用する場合を除く)

SortedSetまた、インターフェース(最も一般的な実装は)に精通している必要がありますTreeSet

SortedSetは、要素の自然な順序付けまたはいくつかのを使用して順序付けされたままのセットです(つまり、要素は一意です)Comparatorfirst()last()メソッドを使用して、最初と最後のアイテムに簡単にアクセスできます。ASortedSetは、コレクションを重複なしで特定の方法で注文する必要がある場合に、ときどき便利です。

編集:要素が挿入順序で保持されているセット(リストのように)が必要な場合は、を参照してくださいLinkedHashSet

于 2009-04-20T19:31:46.687 に答える
18

誰かが正確にこのように綴ったかどうかはわかりませんが、次のことを理解する必要があります。

セットには「最初の」要素はありません。

他の人が言ったように、集合には順序がないからです。セットは、特に順序付けを含まない数学的概念です。

もちろん、コンピューターは、メモリ内で順序付けされていないもののリストを実際に保持することはできません。いくつかの順序が必要です。内部的には、配列またはリンクされたリストなどです。しかし、あなたはそれが何であるかを本当に知りませんし、実際には最初の要素を持っていません。「最初」に出てくる要素は偶然そのように出てきて、次回は最初ではないかもしれません。特定の最初の要素を「保証」するための措置を講じたとしても、たまたま Set の特定の実装に対してそれを正しく取得しただけなので、それは偶然に出てきます。別の実装は、あなたが行ったことでそのように機能しない可能性があります。実際、自分が使用している実装について、自分が思っているほどよくわかっていない可能性があります。

人々はこのすべてに出くわします。THE。時間。RDBMS システムを使用しており、理解できません。RDBMS クエリは、一連のレコードを返します。これは数学のセットと同じタイプです: アイテムの順序付けられていないコレクションです。この場合のみ、アイテムはレコードです。ORDER BY 句を使用しない限り、RDBMS クエリの結果には順序がまったく保証されていません。別の方法で突然、結果が期待どおりの順序で表示されません。これらは通常、クエリ結果の順序が保証されていないことを事前に説明されたときに、データベースクラスで (またはドキュメントやチュートリアルを読むときに) 注意を払わなかった人々です。

于 2009-04-20T21:25:20.407 に答える
10

一部のデータ構造は、標準の Java コレクションにはありません。

バッグ (セットに似ていますが、複数の要素を含めることができます)

UniqueList (順序付きリスト、各要素を一度だけ含むことができます)

この場合、uniquelistが必要になるようです

柔軟なデータ構造が必要な場合は、Google コレクションに興味があるかもしれません

于 2009-04-28T07:29:23.397 に答える
7

確かに、Set コレクションの定義により、Set 内の要素は順序付けられていません。したがって、インデックスでアクセスすることはできません。

しかし、インデックスをパラメーターとして提供するのではなく、探しているものと等しいオブジェクトを提供することによって、get(object) メソッドを使用しないのはなぜですか? このようにして、 equal メソッドで使用される属性を知るだけで、 Set 内の要素のデータにアクセスできます。

于 2010-01-19T12:37:24.913 に答える
7

セット内のインデックスによるランダム アクセスを多数行う場合は、その要素の配列ビューを取得できます。

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]

ただし、主な欠点が 2 つあります。

  1. セット全体の配列を作成する必要があるため、メモリ効率が良くありません。
  2. セットが変更されると、ビューは廃止されます。
于 2011-01-07T11:54:18.463 に答える
5

セットで数値インデックスを使用する唯一の理由は、反復のためです。そのためには、

for(A a : set) { 
   visit(a); 
}
于 2009-04-20T20:25:23.733 に答える
5

これは、Set が一意性のみを保証し、最適なアクセスまたは使用パターンについては何も述べていないためです。つまり、セットはリストまたはマップである可能性があり、それぞれが非常に異なる検索特性を持っています。

于 2009-04-20T19:22:23.247 に答える
3

インデックスを介してアクセスするソート済みセットが実際に必要な状況に遭遇しました(インデックスを使用してソートされていないセットにアクセスすることは意味がないという他のポスターに同意します)。例として、子を並べ替え、重複する子を許可しないツリーが挙げられます。

それらを表示するにはインデックスを介してアクセスする必要があり、設定された属性は重複を効率的に排除するのに役立ちました。

java.util または google コレクションに適切なコレクションが見つからなかったので、自分で簡単に実装できることがわかりました。基本的な考え方は、SortedSet をラップし、インデックスを介したアクセスが必要な場合に List を作成することです (SortedSet が変更された場合はリストを忘れます)。もちろん、これは、ラップされた SortedSet を変更し、リストへのアクセスが Collection の有効期間内に分離されている場合にのみ効率的に機能します。それ以外の場合は、頻繁にソートされるリストのように動作します。つまり、遅すぎます。

多数の子を使用すると、Collections.sort を介してソートし続けたリストよりもパフォーマンスが大幅に向上しました。

于 2010-08-18T13:33:43.910 に答える
1

Setインターフェースに get index-type 呼び出しや、first() や last() などのさらに基本的な呼び出しがない理由は、あいまいな操作であり、潜在的に危険な操作であるためです。メソッドが Set を返し、たとえば first() メソッドを呼び出した場合、ジェネリック Set が順序付けを保証しないとすると、どのような結果が期待されるでしょうか? 結果のオブジェクトは、メソッドの呼び出しごとに非常に大きく異なる可能性があります。または、使用しているライブラリが変更され、その下の実装が変更され、すべてのコードが壊れていることがわかるまで、そうではなく、誤った安心感に陥る可能性があります。特に理由はありません。

ここにリストされている回避策に関する提案は適切です。インデックス アクセスが必要な場合は、リストを使用します。ジェネリック Set で iterators または toArray を使用する場合は注意してください。a) 順序付けが保証されておらず、b) 順序付けが後続の呼び出しまたは異なる基になる実装で変更されないという保証がないためです。間に何かが必要な場合は、SortedSet または LinkedHashSet が必要です。

// Set インターフェイスに get-random-element があればいいのにと思います。

于 2012-05-21T18:13:23.067 に答える
1

セットがソートされてもかまわない場合は、indexed-tree-mapプロジェクトに興味があるかもしれません。

強化された TreeSet/ TreeMapは、インデックスによる要素へのアクセス、または要素のインデックスの取得を提供します。また、実装は、RB ツリー内のノードの重みの更新に基づいています。したがって、ここではリストによる繰り返しやバックアップはありません。

于 2014-01-27T14:09:04.923 に答える
-1

できるよnew ArrayList<T>(set).get(index)

于 2012-02-02T22:55:12.603 に答える
-3

セット内の要素を取得するには、次のものを使用します。

public T getElement(Set<T> set, T element) {
T result = null;
if (set instanceof TreeSet<?>) {
    T floor = ((TreeSet<T>) set).floor(element);
    if (floor != null && floor.equals(element))
    result = floor;
} else {
    boolean found = false;
    for (Iterator<T> it = set.iterator(); !found && it.hasNext();) {
    if (true) {
        T current = it.next();
        if (current.equals(element)) {
        result = current;
        found = true;
        }
    }
    }
}
return result;
}
于 2010-06-20T10:19:55.907 に答える