我希望在List中找到一个匹配项并返回依赖于匹配项的值。 CollectFirst适用于匹配集合的元素,但在这种情况下,我想匹配元素的成员swEl而不是元素本身。
abstract class CanvNode (var swElI: Either[CSplit, VistaT])
{
private[this] var _swEl: Either[CSplit, VistaT] = swElI
def member = _swEl
def member_= (value: Either[CSplit, VistaT] ){ _swEl = value; attach}
def attach: Unit
attach
def findVista(origV: VistaIn): Option[Tuple2[CanvNode,VistaT]] = member match
{
case Right(v) if (v == origV) => Option(this, v)
case _ => None
}
}
def nodes(): List[CanvNode] = topNode :: splits.map(i => List(i.n1, i.n2)).flatten
//Is there a better way of implementing this?
val temp: Option[Tuple2[CanvNode, VistaT]] =
nodes.map(i => i.findVista(origV)).collectFirst{case Some (r) => r}
我是否需要View,或者collectFirst方法是否确保仅根据需要创建集合?
这让我觉得这必须是一个相当普遍的模式。另一个例子可能是,如果一个人拥有主要List元素的List成员,并且想要返回第四个元素(如果有的话)。 我可以调用一种标准方法吗?如果失败,我可以创建以下内容:
implicit class TraversableOnceRichClass[A](n: TraversableOnce[A])
{
def findSome[T](f: (A) => Option[T]) = n.map(f(_)).collectFirst{case Some (r) => r}
}
然后我可以用以下内容替换上面的内容:
val temp: Option[Tuple2[CanvNode, VistaT]] =
nodes.findSome(i => i.findVista(origV))
这使用2.10中的隐式类,对于2.10之前的使用:
class TraversableOnceRichClass[A](n: TraversableOnce[A])
{
def findSome[T](f: (A) => Option[T]) = n.map(f(_)).collectFirst{case Some (r) => r}
}
implicit final def TraversableOnceRichClass[A](n: List[A]):
TraversableOnceRichClass[A] = new TraversableOnceRichClass(n)
答案 0 :(得分:1)
作为介绍性的侧节点:您正在描述的操作(如果存在,则返回第一个Some
,否则返回None
)是Option
下的Option
集合的总和scala> Stream(None, None, Some("a"), None, Some("b")).map(_.fst).asMA.sum
res0: scalaz.FirstOption[java.lang.String] = Some(a)
的“第一个”monoid实例。例如,使用Scalaz 6:
implicit def optionFirstMonoid[A] = new Monoid[Option[A]] {
val zero = None
def append(a: Option[A], b: => Option[A]) = a orElse b
}
或者你可以把这样的东西放在范围内:
.map(_.fst)
跳过mconcat . map (First . Just) $ [1..]
部分。遗憾的是,这些方法在Scalaz中都没有适当的延迟,因此将对整个流进行评估(例如,与Haskell不同,sumr
就好了)。
编辑:作为旁注的旁注:显然Scalaz 提供了适当懒惰的Stream.from(1).map(Some(_).fst).sumr
(对于流 - 这些方法都不适用于视图)。例如,你可以这样写:
n.map(f(_)).collectFirst{ case Some(r) => r }
而不是永远等待你的答案,就像在Haskell版本中一样。
但假设我们坚持使用标准库,而不是:
n.flatMap(f(_)).headOption
我会写下以下内容,或多或少相当,并且可以说更具惯用性:
val xs = List(1, 2, 3, 4, 5)
例如,假设我们有一个整数列表。
map
我们可以使这个懒惰的val ys = xs.view.map { i => println(i); i }
一个带有副作用的函数向我们展示何时访问它的元素:
flatMap
现在我们可以Option
headOption
- 在结果集合上返回函数,并使用scala> ys.flatMap(i => if (i > 2) Some(i.toString) else None).headOption
1
2
3
res0: Option[java.lang.String] = Some(3)
(安全地)返回第一个元素(如果存在):
headOption
很明显,当我们按照需要点击非空值时会停止。是的,如果您的原始集合是严格的,您肯定需要一个视图,否则collectFirst
(或flatMap
)无法返回并停止map
(或{{1在它之前的那个。
在您的情况下,您可以跳过findVista
并使用以下内容更简洁:
val temp = nodes.view.flatMap(
node => node.right.toOption.filter(_ == origV).map(node -> _)
).headOption
当然,无论你发现这个更清楚还是一团糟都是品味问题。