以下命令式代码最有效的函数版本是什么?

发布于 2024-10-09 15:52:46 字数 391 浏览 1 评论 0原文

我正在学习 Scala,我想知道使用 Scala 的函数式编程功能表达这种命令式模式的最佳方式。

def f(l: List[Int]): Boolean = {
  for (e <- l) {
    if (test(e))
      return true
    }
  }
  return false
}

我能想到的最好的办法是:

l map { e => test(e) } contains true

但这效率较低,因为它在每个元素上调用 test() ,而命令式版本则在满足 test() 的第一个元素上停止。是否有更惯用的函数式编程技术可以达到相同的效果?命令式版本在 Scala 中似乎很尴尬。

I'm learning Scala and I want to know the best way of expressing this imperative pattern using Scala's functional programming capabilities.

def f(l: List[Int]): Boolean = {
  for (e <- l) {
    if (test(e))
      return true
    }
  }
  return false
}

The best I can come up with is along the lines of:

l map { e => test(e) } contains true

But this is less efficient since it calls test() on each element, whereas the imperative version stops on the first element that satisfies test(). Is there a more idiomatic functional programming technique I can use to the same effect? The imperative version seems awkward in Scala.

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

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

发布评论

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

评论(3

又爬满兰若 2024-10-16 15:52:46

您可以使用exists方法:

val listWithEvens = List(1,2,3,4)
val listWithoutEvens = List(1,3,5)
def test(e: Int) = e % 2 == 0

listWithEvens.exists(test(_)) // true
listWithoutEvens.exists(test(_)) // false

// alternative
listWithEvens.exists(_ % 2 == 0)  // true 

如果您不熟悉这样使用的_,它相当于:

listWithEvens.exists(v => v % 2 == 0)

You can use the exists method:

val listWithEvens = List(1,2,3,4)
val listWithoutEvens = List(1,3,5)
def test(e: Int) = e % 2 == 0

listWithEvens.exists(test(_)) // true
listWithoutEvens.exists(test(_)) // false

// alternative
listWithEvens.exists(_ % 2 == 0)  // true 

If you are not familiar with the _ used like this, it's the equivalent of:

listWithEvens.exists(v => v % 2 == 0)
美羊羊 2024-10-16 15:52:46

因此,您需要的是 exists 方法 (l.exists(test)),它没有说明您如何实现它。最简单的实现并不是很高效:

def f(l: List[Int]): Boolean = l.foldLeft(false)((flag, n) => flag || test(n))

问题是它将迭代所有 l,即使一旦 flag 变为 true 测试就会停止。现在,大多数函数式迭代方法(在严格的语言中)在完成所有集合之前不会停止迭代。那些实际上的实现方式与您的实现方式非常相似,因此,最终您只是隐藏了此类代码,而不是避免它。

然而,如果我被要求使用现有的方法,当然,不使用 exists,并且在此之上保持高效,人们可以这样做:

def f(l: List[Int]): Boolean = l.dropWhile(!test(_)).nonEmpty

So, what you want is the exists method (l.exists(test)), which says nothing of how you'd implement it. The simplest implementation isn't very efficient:

def f(l: List[Int]): Boolean = l.foldLeft(false)((flag, n) => flag || test(n))

The problem is that it will iterate through all of l, even if the testing stops once flag becomes true. Now, most functional methods of iteration (in strict languages) will not stop iterating until finished through all the collection. The ones that do are actually implemented pretty much like you did, so, in the end, you are just hiding that sort of code, not avoiding it.

However, if I were required to use existing methods, and, of course, not to use exists, and be efficient on top of that, one could do something like this:

def f(l: List[Int]): Boolean = l.dropWhile(!test(_)).nonEmpty
死开点丶别碍眼 2024-10-16 15:52:46

当然,在这种情况下没有必要(我实际上希望 Scala 库为自己的 exists 使用更命令式的版本 - 或者至少有一个 map显式的 break),但在 List 上,您可以使用简单的(尾)递归函数。

import scala.annotation.tailrec

@tailrec
def exists(l: List[Int], p: (Int) => Boolean): Boolean = l match {
  case Nil => false
  case x :: xs => p(x) || exists(xs, p)
}

因为如果左侧为 false,则 || 仅评估右侧,这意味着您会提前中断。

当然,只有当引用集合的尾部成本很低时,这才是有效的。

Of course it isn’t necessary in this case (and I actually expect the Scala library to use a more imperative version for their own exists – or at least have a map with an explicit break in it) but on a List you can use a simple (tail) recursive function.

import scala.annotation.tailrec

@tailrec
def exists(l: List[Int], p: (Int) => Boolean): Boolean = l match {
  case Nil => false
  case x :: xs => p(x) || exists(xs, p)
}

Because || only evaluates the right side if the left side is false it means you break early.

This, of course, is only efficient if referencing the tail of a collection is cheap.

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