Set で重複を排除
入れる前に、毎回 contains で確かめている
同じものを 2 回登録したくないとき、List だとこう書くことになります。
Java
if (!sent.contains(address)) {
sent.add(address);
}List.contains は先頭から 1 件ずつ equals で比べるので、たまっている件数だけ時間がかかります。1 万件たまった状態でさらに 1 万件足すと、比較の回数は 1 億回に近づきます。そのうえ、重複を入れないという約束は if の書き忘れひとつで崩れます。
java.util.HashSet は、重複を許さないことを入れ物の側が保証してくれる型です。
add はすでに有る値を黙って捨てる
Java
import java.util.HashSet;
import java.util.Set;
public class Demo {
public static void main(String[] args) {
Set<String> sent = new HashSet<>();
sent.add("a@example.com");
sent.add("b@example.com");
boolean added = sent.add("a@example.com"); // false
System.out.println(sent.size()); // 2
System.out.println(sent.contains("b@example.com")); // true
}
}add は追加できたときだけ true を返します。すでに同じ値が入っていれば何も起きず false が返るだけで、例外にはなりません。だから重複を気にせず投げ込んでよく、size() を見れば実際に何種類あったかが分かります。
contains も HashSet なら件数が増えてもほぼ一定の速さで答えます。あるかどうかを何度も聞くデータは、List ではなく Set に置いておくのが定石です。
順番は期待できない
HashSet は要素の並び順を保証しません。回すたびに、あるいはプログラムを動かし直すたびに順番が変わることもあります。
Java
Set<String> tags = new LinkedHashSet<>(); // 追加した順に取り出せる
Set<String> sorted = new TreeSet<>(); // 小さい順に並ぶ追加した順に取り出したいなら LinkedHashSet、並べ替えたいなら TreeSet に替えます。メソッドの使い方はどれも同じで、new するクラスを変えるだけです。
もう 1 つ、Set<int> とは書けません。ArrayList のときと同じで、整数を入れるなら Set<Integer> です。set.add(101) のように普通の数値を渡すぶんには、Java が自動で Integer に包んでくれます。
課題では、配列に何種類の値が入っていたかを返します。Set の性質だけで答えが出るので、重複しているかどうかを自分で調べる if は 1 つも要りません。空の配列を渡された場合も、特別な場合分けなしで正しい答えになります。
要件
- クラス名は
Solution、メソッド名はuniqueCount、戻り値の型はint、引数はint[] arrの 1 つ - 重複を排除した要素数を返すこと。
Set(HashSet推奨) を使って実装する - 空配列を渡されたときは
0を返すこと
入出力例
uniqueCount([1,2,2,3,3,3]) → 3
uniqueCount([]) → 0
uniqueCount([5,5,5,5]) → 1
uniqueCount([1,2,3,4]) → 4
uniqueCount([-1,0,-1,0,7]) → 3