2

我经常需要检查许多值是否相等,以防提取共同值。也就是说,我需要一个功能如下:

extract(List()) // None
extract(List(1,2,3)) // None
extract(List(2,2,2)) // Some(2)

假设一个有一个会添加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 中是否有类似的东西——可能更普遍——或者更简单的编写方式?

4

4 回答 4

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

于 2012-09-26T13:26:47.213 回答
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)
于 2012-09-26T13:45:40.323 回答
2

这是一个流畅的解决方案

yourSeq.groupBy(x => x) match {case m if m.size==1 => m.head._1; case _ => None}
于 2012-09-26T14:41:49.833 回答
-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)

您还可以使用 afoldLeft而不是foreach并将空映射用作 的初始累加器foldLeft

于 2012-09-26T13:28:13.160 回答