我经常需要检查许多值是否相等,以及提取公共值。也就是说,我需要一个功能如下:
extract(List()) // None
extract(List(1,2,3)) // None
extract(List(2,2,2)) // Some(2)
假设有一个pimp会将tailOption
添加到seqs(写一个或者scalaz中有一个是微不足道的),一个实现看起来像
def extract[A](l: Seq[A]): Option[A] = {
def combine(s: A)(r: Seq[A]): Option[A] =
r.foldLeft(Some(s): Option[A]) { (acc, n) => acc flatMap { v =>
if (v == n) Some(v) else None
} }
for {
h <- l.headOption
t <- l.tailOption
res <- combine(h)(t)
} yield res
}
有没有类似的东西 - 可能更通用 - 已经在Scalaz中,或者用一些更简单的方法来编写它?
答案 0 :(得分:3)
这似乎是一种非常复杂的写作方式
def extract[A](l:Seq[A]):Option[A] = l.headOption.flatMap(h =>
if (l.tail.forall(h==)) Some(h) else None)
您不需要tailOption
,因为只有当flatMap
不为空时,才会将作为参数传递给l
的匿名函数执行。
答案 1 :(得分:2)
如果您只想删除重复项toSet
就足够了:
def equalValue[A](xs: Seq[A]): Option[A] = {
val set = xs.toSet
if (set.size == 1) Some(set.head) else None
}
scala> equalValue(List())
res8: Option[Nothing] = None
scala> equalValue(List(1,2,3))
res9: Option[Int] = None
scala> equalValue(List(2,2,2))
res10: Option[Int] = Some(2)
答案 2 :(得分:2)
这是一个流畅的解决方案
yourSeq.groupBy(x => x) match {case m if m.size==1 => m.head._1; case _ => None}
答案 3 :(得分:-1)
您可以使用地图计算列表中每个元素的出现次数,然后仅返回多次出现的那些元素:
def extract[T](ts: Iterable[T]): Iterable[T] = {
var counter: Map[T, Int] = Map()
ts.foreach{t =>
val cnt = counter.get(t).getOrElse(0) + 1
counter = counter.updated(t, cnt)
}
counter.filter(_._2 > 1).map(_._1)
}
println(extract(List())) // List()
println(extract(List(1,2,3))) // List()
println(extract(List(2,2,2))) // List(2)
println(extract(List(2,3,2,0,2,3))) // List(2,3)
您还可以使用foldLeft
代替foreach
,并使用空地图作为foldLeft
的初始累加器。