これは簡単なはずだと思いましたが、うまくいきません。プロパティ名を持つケース クラスがあります。名前が重複しているかどうかを確認したい...
employees.groupBy(_.name).mapValues(_.size).filter(_._2 == 1).toSeq.isEmpty
それはうまくいきません.それはすべきですか?
これは簡単なはずだと思いましたが、うまくいきません。プロパティ名を持つケース クラスがあります。名前が重複しているかどうかを確認したい...
employees.groupBy(_.name).mapValues(_.size).filter(_._2 == 1).toSeq.isEmpty
それはうまくいきません.それはすべきですか?
他の答えは機能しgroupBy
ますが、1 万人の従業員がいて、最初の 2 人が同じ名前の場合、コストのかかる操作で非効率的です。
1) 短い方法: (distinct
すべての値の HashSet を内部的に構築します)
val names = employees.map(_.name)
names.distinct != names
2)効率的な方法:(重複を見つける前に必要なだけのseqのみをトラバースします)
def hasDupes(employees: Seq[Employee]): Boolean = {
val names = collection.mutable.Set.empty[String]
employees.foreach { e =>
if (names(e.name)) return true
names += e.name
}
false
}
これは、末尾再帰メソッドを使用してワンライナーとして記述できますが、実際には、不変セットは可変セットよりもはるかに遅いため、効率を重視する場合はあまり良くありません。
3) 型破りな方法: (まったくセットを構築しませんが、クイックソートを開始し、同じ名前が 2 つ見つかるとすぐに (安価な例外を介して) 終了します。効率的である必要があります。)
class Dupe extends Throwable with util.control.NoStackTrace
val dupeOrd = new Ordering[Employee] {
def compare(x: Employee, y: Employee) =
if (x.name == y.name) throw new Dupe else x.name compare y.name
}
def hasDupes(employees: Seq[Employee]) =
try { employees.sorted(dupeOrd); false } catch { case e: Dupe => true }
メソッド 0 が om-nom-nom のものである結果のベンチマークgroupBy
(1000 人の従業員ベクトルで 1000 回実行した場合のミリ秒単位の時間、重複なし):
method time Early return if duplicate found
0 (groupBy) 1560 No
1 (distinct) 329 No
2a (mutable.Set) 255 Yes
2b (immutable.Set) 1414 Yes
3 (sorting) 666 Yes //242 if employees already in name order
ここだから
employees.groupBy(_.name).mapValues(_.size).filter(_._2 == 1).toSeq.isEmpty
== ではなく > 記号が必要です
employees.groupBy(_.name).mapValues(_.size).filter(_._2 > 1).toSeq.isEmpty
まず、一連のタプル (K、V) を返す groupBy を使用してから、それらのそれぞれをマップして、mapValues(_.size) でそれぞれの数を確認し、サイズのレコードがあるかどうかを確認します。 1より大きい。