scala 返回列表中的第一个 Some

发布于 2024-09-18 03:14:58 字数 401 浏览 6 评论 0原文

我有一个列表 l:List[T1] ,目前正在执行以下操作:

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

myfun 函数返回 None 或 Some,flatten 丢弃所有 None,find 返回第一个列表的元素(如果有)。

这对我来说似乎有点老套。我认为可能存在一些理解或类似的东西,可以减少浪费或更聪明。 例如:如果 myfun 在列表 map 期间返回 any Some,我不需要任何后续答案>l。

I have a list l:List[T1] and currently im doing the following:

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

The myfun function returns None or Some, flatten throws away all the None's and find returns the first element of the list if any.

This seems a bit hacky to me. Im thinking that there might exist some for-comprehension or similar that will do this a bit less wasteful or more clever.
For example: I dont need any subsequent answers if myfun returns any Some during the map of the list l.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一世旳自豪 2024-09-25 03:14:58

怎么样:

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

Stream 是惰性的,因此它不会提前映射所有内容,但也不会重新映射内容。不要将事物展平,而是将 Option 转换为 List,以便可以使用 flatMap

How about:

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

Stream is lazy, so it won't map everything in advance, but it won't remap things either. Instead of flattening things, convert Option to List so that flatMap can be used.

慕巷 2024-09-25 03:14:58

除了使用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] 转换元素。

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

从 Scala 2.13 开始,随着 Stream 的弃用而转而使用 LazyList,这将变成:

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

In addition to using toStream to make the search lazy, we can use 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

This:

  • Transforms the List into a Stream in order to stop the search early.

  • Transforms elements using myFun as Option[T]s.

  • Collects the first mapped element which is not None and extract it.

Starting Scala 2.13, with the deprecation of Streams in favor of LazyLists, this would become:

List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }
海之角 2024-09-25 03:14:58

好吧,这几乎,但不完全

val x = (l flatMap myfun).headOption

但是您从 myfun 返回一个 Option 而不是 List,所以这可能不起作用。如果是这样(我手头没有 REPL),请尝试:

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

Well, this is almost, but not quite

val x = (l flatMap myfun).headOption

But you are returning a Option rather than a List from myfun, so this may not work. If so (I've no REPL to hand) then try instead:

val x = (l flatMap(myfun(_).toList)).headOption
旧时光的容颜 2024-09-25 03:14:58

嗯,for-communeration 的等价物非常简单

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

,如果你真的进行翻译,其结果与 oxbow_lakes 给出的结果相同。假设 List.flatmap 有合理的惰性,这既是一个干净又有效的解决方案。

Well, the for-comprehension equivalent is pretty easy

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

which, if you actually do the the translation works out the same as what oxbow_lakes gave. Assuming reasonable laziness of List.flatmap, this is both a clean and efficient solution.

风苍溪 2024-09-25 03:14:58

截至2017年,之前的答案似乎已经过时了。我运行了一些基准测试(1000 万个整数的列表,第一个匹配项大致在中间,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 ms

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

第一次调用 toStream< /code> 在列表上:~1200 ms

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

在列表上调用 toStream.flatMap:~450 ms

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

在列表上调用 flatMap:~100 ms

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

第一次调用 iterator列表中的:约 35 毫秒

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

递归函数 find():约 25 毫秒

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 毫秒

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 而不是 < code>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 的其他实现将显示不同的性能 - 大多数都会更差。)

As of 2017, the previous answers seem to be outdated. I ran some benchmarks (list of 10 million Ints, first match roughly in the middle, Scala 2.12.3, Java 1.8.0, 1.8 GHz Intel Core i5). Unless otherwise noted, list and map have the following types:

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

Simply call map on the list: ~1000 ms

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

First call toStream on the list: ~1200 ms

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

Call toStream.flatMap on the list: ~450 ms

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

Call flatMap on the list: ~100 ms

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

First call iterator on the list: ~35 ms

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

Recursive function 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
    }
  }
}

Iterative function 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
}

You can further speed up things by using Java instead of Scala collections and a less functional style.

Loop over indices in 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
}

Loop over indices in java.util.ArrayList with function returning null instead of 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
}

(Of course, one would usually declare the parameter type as java.util.List, not java.util.ArrayList. I chose the latter here because it's the class I used for the benchmarks. Other implementations of java.util.List will show different performance - most will be worse.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文