Javaで一意/個別のオブジェクト(重複なし)のリストを作成する方法は?
現在、キーが上書きされているため、これを行うためにHashMap<String, Integer>
を使用しています。したがって、最後に一意になるHashMap.getKeySet()
を取得できます。しかし、ここでは価値の部分が無駄になるため、これを行うためのより良い方法があるはずです。
Set 実装を使用できます:
JAVADocからの情報:
重複する要素を含まないコレクション。より正式には、セットにはe1.equals(e2)などの要素e1とe2のペアは含まれず、最大1つのnull要素が含まれます。その名前が示すように、このインターフェイスは数学的集合の抽象化をモデル化します。
注:可変オブジェクトをセット要素として使用する場合は、細心の注意が必要です。オブジェクトがセット内の要素であるときに、等しい比較に影響する方法でオブジェクトの値が変更された場合、セットの動作は指定されません。この禁止の特殊なケースは、セットが自身を要素として含むことは許可されないということです。
これらは実装です:
このクラスは、ハッシュ関数がバケット間で要素を適切に分散すると仮定して、基本操作(追加、削除、包含、サイズ)で一定時間のパフォーマンスを提供します。このセットを反復するには、HashSetインスタンスのサイズ(要素の数)とバッキングHashMapインスタンスの「容量」(バケットの数)の合計に比例する時間が必要です。したがって、反復のパフォーマンスが重要な場合は、初期容量を高く設定しない(または負荷率を低くしすぎない)ことが非常に重要です。
HashSet
を反復する場合、生成された要素の順序は未定義です。
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
この実装は、基本操作(追加、削除、および包含)の保証された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)この方法で等しいとみなされる要素は、セットの観点から見ると等しいです。セットの動作は、その順序が等号と矛盾している場合でも明確に定義されています。 Setインターフェイスの一般的な契約に従わないだけです。
ここでは、他の人がほのめかしたが実際には明確に述べていない元のポスターについて、いくつかのことを明確にしたいと思います。一意のリストが必要だと言うとき、それがまさに順序セットの定義です。 SetインターフェイスとListインターフェイスのその他の主な違いは、Listでは挿入インデックスを指定できることです。ですから、質問は、リストインターフェイスが本当に必要なのか(つまり、サードパーティのライブラリとの互換性などのため)、それともSetインターフェイスを使用するようにソフトウェアを再設計できるのでしょうか?また、インターフェイスで何をしているのかを考慮する必要があります。インデックスで要素を見つけることは重要ですか?セットにはいくつの要素が必要ですか?多くの要素がある場合、順序は重要ですか?
一意の制約のみを持つListが本当に必要な場合、Apache Common Utilsクラスorg.Apache.commons.collections.list.SetUniqueListがあり、これはListインターフェースと一意の制約を提供します。ただし、これはListインターフェイスを壊します。ただし、インデックスを使用してリストを検索する必要がある場合は、これによりパフォーマンスが向上します。 Setインターフェイスを扱うことができ、より小さなデータセットがある場合は、LinkedHashSetが良い方法かもしれません。それはあなたのソフトウェアの設計と意図に依存します。
繰り返しますが、各コレクションには特定の長所と短所があります。一部の高速挿入は遅い読み取り、一部は高速読み取りはあるが低速挿入などです。コレクションのドキュメントでかなりの時間を費やして、各クラスとインターフェイスの詳細を完全に学習することは理にかなっています。
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);
}
}
HashSet<String>
を使用して、一意のオブジェクトのコレクションを維持できます。マップ内のInteger
値が重要な場合は、代わりにマップのcontainsKey
メソッドを使用して、キーがすでにマップ内にあるかどうかをテストできます。
HashSet<String>
(または)任意のSet
実装があなたのために仕事をするかもしれません。 Set
は重複を許可しません。
HashSetの場合、 javadoc です。
これがどれほど効率的かはわかりませんが、単純な文脈で私のために働きました。
List<int> uniqueNumbers = new ArrayList<>();
public void AddNumberToList(int num)
{
if(!uniqueNumbers .contains(num)) {
uniqueNumbers .add(num);
}
}
Java.util.Set<E>
Interfaceの実装クラスの1つを使用することができます。 Java.util.HashSet<String>
コレクションクラス。
重複する要素を含まないコレクション。より正式には、セットにはe1.equals(e2)などの要素e1とe2のペアは含まれず、最大1つのnull要素が含まれます。その名前が示すように、このインターフェイスは数学的集合の抽象化をモデル化します。