如何获得 Scala 中两个列表的平方和?

发布于 2024-12-11 17:27:18 字数 168 浏览 0 评论 0原文

如果我有两个列表,

val first = List(1, 2, 3)
val second = List(4, 5, 6)

我如何获得以下内容?

(1-4)^2 + (2-5)^2 + (3-6)^2

If I have two lists

val first = List(1, 2, 3)
val second = List(4, 5, 6)

How would I obtain the following?

(1-4)^2 + (2-5)^2 + (3-6)^2

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

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

发布评论

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

评论(3

笑饮青盏花 2024-12-18 17:27:18

zip、ma​​p 和 sum:

first.view.zip(second).map(t => t._1 - t._2).map(x => x*x).sum
  • zip 将两个列表的元素组合成一个元组
  • view 用于延迟计算列表,以便不在两个映射调用之间构建结构

(编辑以 sum 替换 reduceLeft))


看到评论后,我觉得我必须回来解释一下视图。基本上,视图将 Traversable 转换为类似迭代器的结构,以便在应用 mapzip 等方法时不必创建多个中间结构> 以及其他一些。 GenIteratableViewLike 的类型成员给人一种哪些操作有特殊处理。因此,通常如果您有一堆按顺序应用的 map、filter、drop、takeWhile,您可以使用 view 来获得一些性能。经验法则是尽早应用 view 以最大程度地减少创建的中间 List 数量,如有必要,在最后使用 force 返回到List(或您正在使用的任何集合)。这就是丹尼尔的建议。

关于性能的问题是,在实践中,如果这很重要,你就必须进行现实检查。以下是一些数字(越低越好):

no view List(62, 62, 62, 62, 63) sum: 311
view before zip List(32, 31, 15, 16, 31) sum: 125
view after zip List(31, 46, 46, 31, 31) sum: 185
iterator List(16, 16, 16, 16, 15) sum: 79
zipped List(62, 47, 62, 46, 47) sum: 264

代码在这里:

import testing.Benchmark

def lots[T](n: Int, f: => T): T = if (n > 0) { f; lots(n - 1, f) } else f

def bench(n: Int, id: String)(block: => Unit) {
  val times = (new testing.Benchmark { 
    def run() = lots(10000, block)
  }).runBenchmark(n)
  println(id + " " + times + " sum: " + times.sum)
}

val first = List(1, 2, 3)
val second = List(4, 5, 6)

bench(5, "no view") { first.zip(second).map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "view before zip") { first.view.zip(second).map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "view after zip") { first.zip(second).view.map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "iterator") { first.iterator.zip(second.iterator).map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "zipped") { (first, second).zipped.map((a,b) => a - b).map(x => x*x).sum }

zip, map and sum:

first.view.zip(second).map(t => t._1 - t._2).map(x => x*x).sum
  • zip combine elements of the two list into a tuple
  • view is used to have the list computed lazily to not build a structure between the two map calls

(edit to replace reduceLeft by sum)


After seeing the comments, I feel I had to come back and explain about views. Basically a view turns a Traversable into an iterator like structure so that multiple intermediate structures don't have to be created when apply methods like map, zip and a few others. The type members of GenIteratableViewLike gives a sense of what operations have special processing. So typically if you have a bunch of map, filter, drop, takeWhile applied in sequence, you can use view to gain some performance. The rule of thumb is to apply view early to minimize how many intermediate List are created and if necessary use force at the end to go back to List (or whatever collection you're using). Thus Daniel's suggestion.

The thing about performance is that in practice if that's important you sort of have to do a reality check. Here are some numbers (lower is better):

no view List(62, 62, 62, 62, 63) sum: 311
view before zip List(32, 31, 15, 16, 31) sum: 125
view after zip List(31, 46, 46, 31, 31) sum: 185
iterator List(16, 16, 16, 16, 15) sum: 79
zipped List(62, 47, 62, 46, 47) sum: 264

Code is here:

import testing.Benchmark

def lots[T](n: Int, f: => T): T = if (n > 0) { f; lots(n - 1, f) } else f

def bench(n: Int, id: String)(block: => Unit) {
  val times = (new testing.Benchmark { 
    def run() = lots(10000, block)
  }).runBenchmark(n)
  println(id + " " + times + " sum: " + times.sum)
}

val first = List(1, 2, 3)
val second = List(4, 5, 6)

bench(5, "no view") { first.zip(second).map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "view before zip") { first.view.zip(second).map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "view after zip") { first.zip(second).view.map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "iterator") { first.iterator.zip(second.iterator).map(t => t._1 - t._2).map(x => x*x).sum }
bench(5, "zipped") { (first, second).zipped.map((a,b) => a - b).map(x => x*x).sum }
沦落红尘 2024-12-18 17:27:18

一般来说,如果函数很复杂,您可能想要定义一个函数,而不是应用多个映射。您可以将其作为辅助方法执行,或者以匿名方式内联执行。

def op(i: Int, j: Int) = { val m = i - j; m * m }

(first, second).zipped.map(op).sum

或者

(first, second).zipped.map( (i, j) => { val m = i - j; m * m } ).sum

在这些情况下 zippedzip 更方便,因为它可以映射到带有 2 个参数的函数,而不是必须使用的单个元组._1._2 字段。

In general you probably want to define a function if it's anything complex, rather than applying multiple maps. You can do this as a helper method, or anonymously in-line.

def op(i: Int, j: Int) = { val m = i - j; m * m }

(first, second).zipped.map(op).sum

Or

(first, second).zipped.map( (i, j) => { val m = i - j; m * m } ).sum

zipped is a bit more convenient than zip in these situations, because it can be mapped to a function taking 2 arguments, rather than a single tuple on which you have to use the ._1 and ._2 fields.

澉约 2024-12-18 17:27:18

向左折叠:

(0 /: first.zip (second)) ((a, b) => a + (b._1 - b._2)*(b._1 - b._2))

从拉链开始。

with a left fold:

(0 /: first.zip (second)) ((a, b) => a + (b._1 - b._2)*(b._1 - b._2))

starting with a zip.

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