web-dev-qa-db-ja.com

Java.util.Setにget(int index)がないのはなぜですか?

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

セットは物を入れるのに素晴らしいようですが、そこから単一のアイテムを取得するエレガントな方法を見つけることはできません。

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

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

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

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

ただし、シナリオは焦点を絞ったままであるため、シナリオがなければ問題はより有効です。

setとlistの違いは何ですか?.

以下の素晴らしい回答をありがとう。

227
Marty Pitt

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

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

171
Michael Myers

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

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

この「IndexedSet」はSortedSetと同じではありません-SortedSetでは、Comparatorを使用して(または「自然な」順序を使用して)要素がソートされます。

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

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

JDKはオープンソースであるため、このインターフェイスは最終的にJava 7 ...に含まれるでしょう。

73

mmyers 'answer で言及されていない点を1つ追加するだけです。

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

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

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

SortedSetは、要素の自然順序付けによって、またはComparatorを使用して順序付けられたままになっているSet(つまり、要素は一意です)です。 first()およびlast()メソッドを使用して、最初と最後のアイテムに簡単にアクセスできます。 SortedSetは、コレクションを重複のない状態に保ち、特定の方法で順序付けする必要がある場合に時々役立ちます。

Edit:要素が挿入順で保持されているセット(リストのような)が必要な場合は、 LinkedHashSetを見てください。

28
Jonik

この種のことは、いつセットを使用すべきか、いつリストを使用すべきかという質問につながります。通常、アドバイスは次のとおりです。

  1. 順序付けされたデータが必要な場合は、リストを使用します
  2. 一意のデータが必要な場合は、セットを使用します
  3. 両方が必要な場合は、SortedSet(コンパレータで順序付けられたデータ用)またはOrderedSet/UniqueList(挿入で順序付けられたデータ用)のいずれかを使用します。残念ながら、Java AP​​IにはまだOrderedSet/UniqueListがありません。

よくある4番目のケースは、どちらも必要ないことです。この場合、リストを使用するプログラマーとセットを使用するプログラマーがいます。個人的には、順序なしでリストとしてセットを見るのは非常に有害だと思います-それは本当に他の獣だからです。一意性の設定や同等性の設定などが必要な場合を除き、常にリストを優先します。

24
waxwing

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

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

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

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

人々はこれに遭遇します。 。時間。 RDBMSシステムで理解していない。 RDBMSクエリはレコードのセットを返します。これは数学の同じタイプのセットです。アイテムの順不同のコレクションです。この場合のみ、アイテムはレコードです。 ORDER BY句を使用しない限り、RDBMSクエリの結果には順序が保証されませんが、データまたはコードの形状がわずかに変化し、クエリオプティマイザーが動作するようになると、人々はいつでもそれを想定して自分自身をトリップします別の方法で、突然、期待した順序で結果が出ません。これらは通常、クエリ結果の順序が保証されていないことを前もって説明したときに、データベースクラス(またはドキュメントやチュートリアルを読むとき)に注意を払わなかった人々です。

17
skiphoppy

標準のJavaコレクションから一部のデータ構造が欠落しています。

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

UniqueList(順序付きリスト、各要素を1回だけ含めることができます)

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

柔軟なデータ構造が必要な場合は、 Googleコレクション

10

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

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

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

  1. セット全体の配列を作成する必要があるため、メモリ効率がよくありません。
  2. セットが変更されると、ビューは廃止されます。
7
fortran

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

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

7
walls

セットで数値インデックスを使用することについて考えることができる唯一の理由は、反復のためです。そのために、使用

for(A a : set) { 
   visit(a); 
}
5
Hugo

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

5
jsight

私は実際にSortedインデックスを介したアクセスで設定したい状況に遭遇しました(インデックスでソートされていないセットにアクセスしても意味がないという他のポスターと同意します)。例としては、子をソートし、子の複製を許可しないツリーがあります。

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

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

多数の子供がいるため、Collections.sortでソートされたリストよりもパフォーマンスが大幅に向上しました。

3
buchweizen

インデックスを介してアクセスできるのは2つの基本データ構造のみであることに注意してください。

  • 配列データ構造は、O(1)時間の複雑さでインデックスを介してアクセスでき、get(int index)操作を実現します。
  • LinkedListデータ構造にもインデックス経由でアクセスできますが、O(n)操作を実現するためのget(int index)時間の複雑さを伴います。

Javaでは、ArrayListArrayデータ構造を使用して実装されます。

Setデータ構造は通常HashTable/HashMapまたはBalancedTreeデータ構造を介して実装でき、要素が存在するかどうかを迅速に検出し、存在しないものを追加します通常、適切に実装された要素Setは、O(1)時間の複雑さcontains操作を達成できます。 Javaでは、HashSetは最も一般的に使用されるSetの実装であり、HashMap APIを呼び出すことで実装され、HashMapリンクリストとの個別チェーン(-の組み合わせArrayおよびLinkedList)。

Setは異なるデータ構造を介して実装できるため、get(int index)メソッドはありません。

2
coderz

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

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

// Setインターフェイスにget-random-elementがあったらいいのですが。

1
Dan

インデックスを介してアクセスするための代替オプションとしてこのコードを試してください

import Java.io.*;
import Java.util.*;
class GFG {
public static void main (String[] args) {
    HashSet <Integer> mySet=new HashSet<Integer>();
    mySet.add(100);
    mySet.add(100);
    int n = mySet.size();
    Integer arr[] = new Integer[n];
    arr = mySet.toArray(arr);
    System.out.println(arr[0]);
    }
}

これにより100が印刷されます。

1
Prithvi Venu

Java.util.Setは、順序付けられていないアイテムのコレクションです。 Setにはget(int index)がある場合、Setにはインデックスがなく、値を推測することしかできないため、意味がありません。

これが本当に必要な場合は、Setからランダム要素を取得するメソッドをコーディングします。

1

セットがソートされることを気にしない場合は、 indexed-tree-map プロジェクトをご覧ください。

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

0

あなたはnew ArrayList<T>(set).get(index)を行うことができます

0
Janus Troelsen