我有一个清单 l:List[T1] 目前,我正在做以下操作:

myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)

myfun 函数返回无或某些,平坦的扔掉了所有的,并找到返回列表的第一个元素,如果有的话。

对我来说,这似乎有点骇人听闻。我认为可能存在一些易于理解或类似的事情,而这会减少浪费或更聪明。例如:如果我不需要任何后续答案 myfun 返回 任何 Some 在此期间 map 列表 l.

有帮助吗?

解决方案

怎么样:

l.toStream flatMap (myfun andThen (_.toList)) headOption

流是懒惰的,因此不会提前绘制所有内容,但也不会重新映射内容。而不是变平的,而是转换 OptionList 以便 flatMap 可以使用。

其他提示

好吧,这是 几乎,但不完全

val x = (l flatMap myfun).headOption

但是你正在返回 Option 而不是一个 List 从myfun那里,所以这可能行不通。如果是这样(我没有重复),然后尝试:

val x = (l flatMap(myfun(_).toList)).headOption

除了使用 toStream 为了使搜索懒惰,我们可以使用 Stream::collectFirst:

List(1, 2, 3, 4, 5, 6, 7, 8).toStream.map(myfun).collectFirst { case Some(d) => d }
// Option[String] = Some(hello)
// given def function(i: Int): Option[String] = if (i == 5) Some("hello") else None

这:

  • 改变 List 进入 Stream 为了尽早停止搜索。

  • 使用 myFun 作为 Option[T]s。

  • 收集第一个映射元素 None 并提取它。

开始 Scala 2.13, ,贬低 Stream支持 LazyListS,这将成为:

List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }

好吧,对等效的概念非常容易

(for(x<-l, y<-myfun(x)) yield y).headOption

如果您实际上进行了翻译,则与Oxbow_lakes所提供的相同。假设列表合理的懒惰。flatmap,这既是干净有效的解决方案。

截至2017年,先前的答案似乎已经过时了。我进行了一些基准测试(1000万个INT列表,大致在中间大致匹配,Scala 2.12.3,Java 1.8.0,1.8 GHz Intel Core i5)。除非另有说明, listmap 有以下类型:

list: scala.collection.immutable.List
map: A => Option[B]

只需致电 map 在列表中:〜1000毫秒

list.map(map).find(_.isDefined).flatten

第一次通话 toStream 在列表中:〜1200毫秒

list.toStream.map(map).find(_.isDefined).flatten

称呼 toStream.flatMap 在列表中:〜450毫秒

list.toStream.flatMap(map(_).toList).headOption

称呼 flatMap 在列表中:〜100毫秒

list.flatMap(map(_).toList).headOption

第一次通话 iterator 在列表中:〜35毫秒

list.iterator.map(map).find(_.isDefined).flatten

递归功能 find(): :〜25 ms

def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
  list match {
    case Nil => None
    case head::tail => map(head) match {
      case None => find(tail, map)
      case result @ Some(_) => result
    }
  }
}

迭代功能 find(): :〜25 ms

def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
  for (elem <- list) {
    val result = map(elem)
    if (result.isDefined) return result
  }
  return None
}

您可以通过使用Java代替Scala集合和功能较低的样式来进一步加快事物的速度。

在索引中循环 java.util.ArrayList: :〜15 ms

def find[A,B](list: java.util.ArrayList[A], map: A => Option[B]) : Option[B] = {
  var i = 0
  while (i < list.size()) {
    val result = map(list.get(i))
    if (result.isDefined) return result
    i += 1
  }
  return None
}

在索引中循环 java.util.ArrayList 功能返回 null 代替 None: :〜10 ms

def find[A,B](list: java.util.ArrayList[A], map: A => B) : Option[B] = {
  var i = 0
  while (i < list.size()) {
    val result = map(list.get(i))
    if (result != null) return Some(result)
    i += 1
  }
  return None
}

(当然,通常会将参数类型声明为 java.util.List, , 不是 java.util.ArrayList. 。我选择了后者,因为这是我用于基准测试的课程。其他实现 java.util.List 将显示出不同的性能 - 大多数会更糟。)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top