加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala – 迭代两个数组

发布时间:2020-12-16 19:10:03 所属栏目:安全 来源:网络整理
导读:如何迭代两个相同大小的数组,每次迭代访问相同的索引 Scala Way?? for ((aListItem,bListItem) - (aList,bList)) { // do something with items } 应用于Scala的Java方法: for(i - 0 until aList.length ) { aList(i) bList(i) } 假设两个列表大小相同. 解
如何迭代两个相同大小的数组,每次迭代访问相同的索引 Scala Way??

for ((aListItem,bListItem) <- (aList,bList)) {
         // do something with items
      }

应用于Scala的Java方法:

for(i <- 0 until aList.length ) {
          aList(i)
          bList(i)
      }

假设两个列表大小相同.

解决方法

tl;博士:在速度和便利之间需要权衡;你需要知道你的用例才能适当选择.

如果您知道两个数组的长度相同而且您不需要担心它的速度有多快,那么最简单和最规范的就是在for-comprehension中使用zip:

for ((a,b) <- aList zip bList) { ??? }

但是,zip方法会创建一个新的单个数组.为了避免这种开销,你可以在一个元组上使用zipped,它会将元素成对呈现给foreach和map等方法:

(aList,bList).zipped.foreach{ (a,b) => ??? }

更快的是索引数组,特别是如果数组包含像Int这样的基元,因为上面的通用代码必须将它们包装起来.您可以使用方便的方法索引:

for (i <- aList.indices) { ??? }

最后,如果你需要尽可能快地进行,你可以回到手动while循环或递归,如下所示:

// While loop
var i = 0
while (i < aList.length) {
  ???
  i += 1
}

// Recursion
def loop(i: Int) {
  if (i < aList.length) {
    ???
    loop(i+1)
  }
}
loop(0)

如果你计算一些值,而不是让它成为一个副作用,如果你传递它,它有时会更快地递归:

// Recursion with explicit result
def loop(i: Int,acc: Int = 0): Int =
  if (i < aList.length) {
    val nextAcc = ???
    loop(i+1,nextAcc)
  }
  else acc

由于您可以在任何地方删除方法定义,因此可以不受限制地使用递归.您可以添加一个@ annotation.tailrec注释,以确保它可以编译为带有跳转的快速循环,而不是实际占用堆栈空间的递归.

采用所有这些不同的方法来计算长度为1024的向量上的点积,我们可以将它们与Java中的参考实现进行比较:

public class DotProd {
  public static int dot(int[] a,int[] b) {
    int s = 0;
    for (int i = 0; i < a.length; i++) s += a[i]*b[i];
    return s;
  }
}

加上一个等价的版本,我们采用字符串长度的点积(所以我们可以评估对象与原语)

normalized time
-----------------
primitive  object  method
---------  ------  ---------------------------------
 100%       100%   Java indexed for loop (reference)
 100%       100%   Scala while loop
 100%       100%   Scala recursion (either way)
 185%       135%   Scala for comprehension on indices
2100%       130%   Scala zipped
3700%       800%   Scala zip

当然,这对于原始人来说尤其糟糕! (如果你尝试在Java中使用Integer的ArrayLists而不是Array of int,你会得到类似的巨大跳跃.)特别注意,如果存储了对象,zipped是一个非常合理的选择.

但要注意过早优化!拉链等功能形式在清晰度和安全性方面具有优势.如果你总是写while循环,因为你认为“每一点点都有帮助”,你可能会犯一个错误,因为它需要更多的时间来编写和调试,你可能正在利用那段时间来优化程序中一些更重要的部分.

但是,假设您的阵列长度相同是危险的.你确定吗?您需要付出多少努力才能确定?也许你不应该做出这样的假设?

如果您不需要快速,只需更正,那么如果两个数组的长度不同,则必须选择该怎么做.

如果你想对所有元素做一些事情,直到较短的长度,那么zip仍然是你使用的:

// The second is just shorthand for the first
(aList zip bList).foreach{ case (a,b) => ??? }
for ((a,b) <- (aList zip bList)) { ??? }

// This avoids an intermediate array
(aList,b) => ??? }

如果您想要使用默认值填充较短的那个,那么您可以

aList.zipAll(bList,aDefault,bDefault).foreach{ case (a,b) <- aList.zipAll(bList,bDefault)) { ??? }

在任何这些情况下,您都可以使用yield with for或map而不是foreach来生成集合.

如果您需要计算索引或者它确实是一个数组,并且您确实需要快速,则必须手动进行计算.填充缺失的元素很尴尬(我将其作为练习留给读者),但基本形式将是:

for (i <- 0 until math.min(aList.length,bList.length)) { ??? }

然后你使用i索引到aList和bList.

如果你真的需要最大速度,你将再次使用(尾部)递归或while循环:

val n = math.min(aList.length,bList.length)
var i = 0
while (i < n) {
  ???
  i += 1
}

def loop(i: Int) {
  if (i < aList.length && i < bList.length) {
    ???
    loop(i+1)
  }
}
loop(0)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读