1

Scala 的 List 类具有indexWhere方法,这些方法返回与提供的谓词匹配的 List 元素的单个索引(如果不存在,则返回 -1)。

我最近发现自己想收集与给定谓词匹配的 List 中的所有索引,并发现自己编写了如下表达式:

list.zipWithIndex.filter({case (elem, _) => p(elem)}).map({case (_, index) => index})

这里p是一些用于选择匹配元素的谓词函数。对于这样一个简单的要求,这似乎有点笨拙(但我可能会错过一两个技巧)。

我有一半希望indicesWhere在 List 上找到一个可以让我改写的函数:

list.indicesWhere(p)

像这样的东西应该是 Scala 的 List API 的一部分,还是有比我上面展示的更简单的表达式来做同样的事情?

4

2 回答 2

4

好吧,这是一个更短的表达式,它消除了你的一些语法噪音(修改为使用 Travis 的建议):

list.zipWithIndex.collect { case (x, i) if p(x) => i }

或者:

for ((x,i) <- list.zipWithIndex if p(x)) yield i

但是如果你经常使用它,你应该将它添加为一个隐式方法:

class EnrichedWithIndicesWhere[T, CC[X] <: Seq[X]](xs: CC[T]) {
  def indicesWhere(p: T => Boolean)(implicit bf: CanBuildFrom[CC[T], Int, CC[Int]]): CC[Int] = {
    val b = bf()
    for ((x, i) <- xs.zipWithIndex if p(x)) b += i
    b.result
  }
}
implicit def enrichWithIndicesWhere[T, CC[X] <: Seq[X]](xs: CC[T]) = new EnrichedWithIndicesWhere(xs)

val list = List(1, 2, 3, 4, 5)
def p(i: Int) = i % 2 == 1
list.indicesWhere(p)         // List(0, 2, 4)
于 2012-12-28T17:11:04.630 回答
3

您可以使用 unzip 替换地图:

list.zipWithIndex.filter({case (elem, _) => p(elem)}).unzip._2
于 2012-12-28T16:35:33.247 回答