Scala 2.7中的collect方法

3
我正在寻找Scala 2.7中的“collect”方法,但似乎找不到适用的调用。是否有类似于“collect”的东西可以在Scala中使用?
明确一下,我想要从列表中过滤元素,并将这些过滤器映射到新类型。

1
请注意,filterMap 已更名为 collect - Daniel C. Sobral
3个回答

7

您可以使用flatMap方法(2.7版本的完整方法签名为 def flatMap[B](f: (A) => Iterable[B]): List[B])。它在IterableIterator上都声明了(具有略微不同的签名):

scala> val l = List("1", "Hello", "2")
l: List[java.lang.String] = List(1, Hello, 2)

scala> val ints = l.flatMap { s => try { Some(s.toInt) } catch { case _ => None } }
ints: List[Int] = List(1, 2)

在上面的例子中,我利用了Predef中的一个显式转换option2iterable。它在2.8版本中在TraversableLike中声明:
def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That

我想这比collect创建更多对象,因为它会将所有内容都包装在Some中。除此之外,使用flatMapcollect还有其他的区别吗? - Cristian Vrabie

7

通常我使用 flatMap/Option,就像Chris所描述的那样,但有时有一种更复杂的选择,它更加令人愉悦:

class Filter[A](f: Any => Option[A]) {
  def unapply(a: Any) = f(a)
}

object Filter {
  def apply[A](f: Any => Option[A]) = new Filter(f)
}

val evens = Filter {
  case n: Int if n % 2 == 0 => Some(n)
  case _ => None
}

使用方法:

scala> for (evens(n) <- List.range(0,10)) yield n
res0: List[Int] = List(0, 2, 4, 6, 8)

你可以叫我 Chris,Daniel! - oxbow_lakes
或者一行代码:for (i <- 1 to 10 if i % 2 == 0) yield i * 2 - retronym
@retronym 说得没错,但是有些模式匹配是无法使用过滤器实现的。例如(也许是唯一的),类型检查。 - Daniel C. Sobral
1
从技术上讲,它仍然可以完成,尽管不是特别直观:for { a@(x: Int) <- Seq(1, "1", 2, "2") if a % 2 == 0} yield a。如您所知,#900阻止了for { x: Int <- ...。奇怪的是, for { a@(_: Int) <- 不起作用。 - retronym
我从未考虑过那种替代方案。我也不会期望它能够生效。每天都要学点新东西。 :-) - Daniel C. Sobral

1
scala> List(-1,-2, 1,2,3).filter{i => (i % 2) == 0}.map{i => i / 2} 

line10: scala.List[scala.Int] = List(-1,1) 

你需要将这两个调用分开

来自一篇非常有用的博客


2
你根本不需要将调用分开。 - oxbow_lakes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接