118

Javaで一意/個別のオブジェクト(重複なし)のリストを作成するにはどうすればよいですか?

現在HashMap<String, Integer>、キーが上書きされているため、これを行うために使用しています。したがって、最終的に、HashMap.getKeySet()一意のキーを取得できます。しかし、ここでは価値のある部分が無駄になっているので、これを行うためのより良い方法があるはずです。

4

7 に答える 7

190

Set実装を使用できます。

JAVADocからのいくつかの情報:

重複する要素を含まないコレクション。より正式には、セットには、e1.equals(e2)のような要素e1とe2のペアは含まれず、最大で1つのnull要素が含まれます。その名前が示すように、このインターフェースは数学的な集合の抽象化をモデル化します。

注:可変オブジェクトをセット要素として使用する場合は、細心の注意を払う必要があります。オブジェクトがセット内の要素であるときに、等しい比較に影響を与える方法でオブジェクトの値が変更された場合、セットの動作は指定されません。この禁止の特別な場合は、セットがそれ自体を要素として含むことは許可されないということです。

これらは実装です:

  • HashSet

    このクラスは、ハッシュ関数が要素をバケット間で適切に分散することを前提として、基本操作(追加、削除、包含、およびサイズ設定)に対して一定時間のパフォーマンスを提供します。このセットを反復処理するには、HashSetインスタンスのサイズ(要素の数)とバッキングHashMapインスタンスの「容量」(バケットの数)の合計に比例する時間が必要です。したがって、反復パフォーマンスが重要な場合は、初期容量を高く設定しすぎない(または負荷率を低く設定しすぎない)ことが非常に重要です。

    反復する場合、HashSet生成される要素の順序は定義されていません。

  • LinkedHashSet

    予測可能な反復順序を使用した、Setインターフェイスのハッシュテーブルとリンクリストの実装。この実装は、すべてのエントリを介して実行される二重リンクリストを維持するという点でHashSetとは異なります。このリンクリストは、要素がセットに挿入された順序(挿入順序)である反復順序を定義します。要素がセットに再挿入されても、挿入順序は影響を受けないことに注意してください。(s.contains(e)が呼び出しの直前にtrueを返すときに、s.add(e)が呼び出された場合、要素eはセットsに再挿入されます。)

    したがって、上記のコードの出力は...

     Set<Integer> linkedHashSet = new LinkedHashSet<>();
     linkedHashSet.add(3);
     linkedHashSet.add(1);
     linkedHashSet.add(2);
    
     for (int i : linkedHashSet) {
         System.out.println(i);
     }
    

    ...必然的に

    3
    1
    2
    
  • TreeSet

    この実装は、基本操作(追加、削除、および含む)に保証されたlog(n)時間コストを提供します。デフォルトでは、反復で返される要素は「自然順序付け」でソートされるため、上記のコードは...

     Set<Integer> treeSet = new TreeSet<>();
     treeSet.add(3);
     treeSet.add(1);
     treeSet.add(2);
    
     for (int i : treeSet) {
         System.out.println(i);
     }
    

    ...これを出力します:

    1
    2
    3
    

    Comparator(インスタンスをコンストラクターに渡してTreeSet、要素を別の順序で並べ替えることもできます。)

    Setインターフェースを正しく実装するためには、セットによって維持される順序(明示的なコンパレーターが提供されているかどうかに関係なく)がequalsと一致している必要があることに注意してください。(equalsとの整合性の正確な定義については、ComparableまたはComparatorを参照してください。)これは、Setインターフェイスがequals操作で定義されているためですが、TreeSetインスタンスはcompareTo(またはcompare)メソッドを使用してすべての要素の比較を実行します。この方法で等しいと見なされる要素は、セットの観点からは等しいです。セットの動作は、その順序がequalsと矛盾している場合でも明確に定義されています。Setインターフェースの一般的な契約に従わないだけです。

于 2012-11-06T21:18:05.053 に答える
16

他の人がほのめかしているが、実際には明確に述べていない元のポスターについて、ここでいくつかのことを明確にしたいと思います。一意のリストが必要だと言うとき、それはまさに順序集合の定義です。SetインターフェイスとListインターフェイスのその他の重要な違いは、Listでは挿入インデックスを指定できることです。それで、問題は、本当にリストインターフェイスが必要なのか(つまり、サードパーティライブラリとの互換性のためなど)、またはソフトウェアを再設計してセットインターフェイスを使用できるのかということです。また、インターフェイスで何をしているのかを考慮する必要があります。インデックスで要素を見つけることは重要ですか?セットにいくつの要素を期待しますか?多くの要素を使用する場合、順序付けは重要ですか?

一意の制約があるだけのリストが本当に必要な場合は、Apache Common Utilsクラスorg.apache.commons.collections.list.SetUniqueListがあり、リストインターフェイスと一意の制約を提供します。ただし、これはリストインターフェイスを壊します。ただし、インデックスでリストを検索する必要がある場合は、これによりパフォーマンスが向上します。Setインターフェースを処理でき、データセットが小さい場合は、LinkedHashSetが適している可能性があります。それはあなたのソフトウェアのデザインと意図に依存します。

繰り返しますが、各コレクションには特定の長所と短所があります。速い挿入で遅い読み取り、速い読み取りで遅い挿入などがあります。コレクションのドキュメントでかなりの時間を費やして、各クラスとインターフェイスの詳細について完全に学習することは理にかなっています。

于 2014-12-14T18:23:50.653 に答える
11

new HashSet<String> 例を使用してください:

import java.util.HashSet;
import java.util.Set;

public class MainClass {
  public static void main(String args[]) {
    String[] name1 = { "Amy", "Jose", "Jeremy", "Alice", "Patrick" };

    String[] name2 = { "Alan", "Amy", "Jeremy", "Helen", "Alexi" };

    String[] name3 = { "Adel", "Aaron", "Amy", "James", "Alice" };

    Set<String> letter = new HashSet<String>();

    for (int i = 0; i < name1.length; i++)
      letter.add(name1[i]);

    for (int j = 0; j < name2.length; j++)
      letter.add(name2[j]);

    for (int k = 0; k < name3.length; k++)
      letter.add(name3[k]);

    System.out.println(letter.size() + " letters must be sent to: " + letter);

  }
}
于 2012-11-06T21:18:29.197 に答える
5

これがどれほど効率的かはわかりませんが、単純なコンテキストでうまくいきました。

List<int> uniqueNumbers = new ArrayList<>();

   public void AddNumberToList(int num)
    {
        if(!uniqueNumbers .contains(num)) {
            uniqueNumbers .add(num);
        }
    }
于 2018-06-28T07:49:06.343 に答える
4

を使用しHashSet<String>て、一意のオブジェクトのコレクションを維持できます。マップのInteger値が重要な場合は、代わりにマップのcontainsKey方法を使用して、キーがすでにマップにあるかどうかをテストできます。

于 2012-11-06T21:17:13.023 に答える
3

HashSet<String>(または)どのSet実装でもあなたに代わって仕事をするかもしれません。Set重複を許可しないでください。

これがHashSetのjavadocです。

于 2012-11-06T21:17:05.590 に答える
1

java.util.Set<E>インターフェースの実装クラスの1つ、たとえばjava.util.HashSet<String> コレクションクラスを使用することをお勧めします。

重複する要素を含まないコレクション。より正式には、セットには、e1.equals(e2)のような要素e1とe2のペアは含まれず、最大で1つのnull要素が含まれます。その名前が示すように、このインターフェースは数学的な集合の抽象化をモデル化します。

于 2012-11-06T21:17:01.990 に答える