While 循环 - Scala

Posted

技术标签:

【中文标题】While 循环 - Scala【英文标题】:While loop - Scala 【发布时间】:2017-09-13 18:02:29 【问题描述】:

1) 是否可以在 Scala 中使用 while 循环遍历数组?

2) 如何使用reduce循环找到大于50的数字?

val reduce_left_list=List(12,34,54,50,82,34,78,90,3,45,43,1,2343,234)

val greatest_num=reduce_left_list.reduceLeft((x:Int)=>  for(line <- reduce_left_list) line > 50)

【问题讨论】:

只是让你知道,一连串的反对票可能是因为你没有给出任何尝试的迹象,除了“我去吃午饭的时候做我的功课”类型的请求被倾倒在其他人。 【参考方案1】:

也许你想试试filter:

List(12,34,54,50,82,34,78,90,3,45,43,1,2343,234).filter(_ > 50)

【讨论】:

【参考方案2】:

1) 是否可以在 Scala 中使用 while 循环遍历数组?

这取决于您对“遍历数组”的定义。你当然可以做你在 C 中做的同样的事情,例如,取一个整数,在循环的每次迭代中将它增加 1,当它等于数组的大小时停止,并使用这个整数作为数组的索引:

val anArray = Array('A, 'B, 'C, 'D)

var i = 0
val s = anArray.size

while (i < s) 
  println(anArray(i))
  i += 1

// 'A
// 'B
// 'C
// 'D

但我不会将其称为“遍历数组”。您正在遍历整数,而不是数组。

此外,如果您可以tell the array to iterate itself,您为什么要这样做?

anArray foreach println
// 'A
// 'B
// 'C
// 'D

如果您绝对坚持自己处理索引(但同样,您为什么要这样做),有比使用 while 循环更好的方法。例如,您可以遍历 Range:

(0 until s) foreach (i ⇒ println(anArray(i)))

或使用for 理解编写:

for (i ← 0 until s) println(anArray(i))

循环在 Scala 中从不惯用。虽然 Scala 确实 允许副作用,但通常惯用的做法是避免它们并争取引用透明性。引用阿尔伯特·爱因斯坦的话说:“疯狂是在做同样的事情并期待不同的结果”,但这正是我们期望循环做的事情:循环一遍又一遍地执行相同的代码,但我们期望它每次都做不同的事情(或至少一次,即停止循环)。根据爱因斯坦的说法,循环是疯狂的,我们有什么资格挑战爱因斯坦?

说真的:循环不能在没有副作用的情况下工作,但 Scala 社区试图避免副作用,因此 Scala 社区试图避免循环。

2) 如何使用reduce循环找到大于50的数字?

Scala 中没有“减少循环”之类的东西。我想,你的意思是reduce method。

答案是:不。类型不对齐。 reduce 返回一个与集合的元素类型相同类型的值,但是你想返回一个元素的集合。

但是,您可以使用折叠,更准确地说,right fold:

(reduce_left_list :\ List.empty[Int])((el, acc) => if (el > 50) el :: acc else acc)
//=> List(54, 82, 78, 90, 2343, 234)

如果你之后反转结果,你也可以使用left fold:

(List.empty[Int] /: reduce_left_list)((acc, el) => if (el > 50) el :: acc else acc) reverse
//=> List(54, 82, 78, 90, 2343, 234)

如果您尝试将元素附加到结果中,您的运行时间将是二次的而不是线性的:

(List.empty[Int] /: reduce_left_list)((acc, el) => if (el > 50) acc :+ el else acc)
//=> List(54, 82, 78, 90, 2343, 234)

但是,说“你可以使用左/右折叠来做到这一点”是重言式:左/右折叠是通用,这意味着任何事情你可以做使用集合,可以通过左/右折叠来完成。这意味着使用左/右折叠并不是很能揭示意图:因为左/右折叠可以做任何事情,所以在代码中看到左/右折叠并不能告诉读者发生了什么。

因此,只要有可能,您应该使用更专业的操作和更能表达意图的名称。在这种特殊情况下,您希望过滤掉一些满足谓词的特定元素。 Scala 集合 API 实际上有一个过滤方法,它被称为(惊喜!)filter

reduce_left_list filter (_ > 50)
//=> List(54, 82, 78, 90, 2343, 234)

或者,您可以改用withFilter

reduce_left_list withFilter (_ > 50)

不同之处在于filter 返回一个新列表,而withFilter 返回FilterMonadic 的一个实例,它是现有列表的视图只包含满足谓词的元素。

【讨论】:

我同意一般来说不应该“遍历数组”。但是当您问为什么有人会这样做时:我总是在性能关键代码(数值计算)中这样做。所有函数式方法,例如 .map 甚至 scala 中的 for,都隐式使用函数调用来运行循环内容代码。这有一个成本,仅对于真正关键的性能代码,应该避免。此外,使用函数式方法很容易创建许多无用的中间集合(但可以避免)。基本上在这些情况下,我使用可变集合和 while-loop 编写 c 风格的代码。

以上是关于While 循环 - Scala的主要内容,如果未能解决你的问题,请参考以下文章

Scala自定义while循环

scala while循环赋值

Scala基础学习之for循环和while循环

scala的4中for循环,及while和do while循环

在 Scala 中编写 read-while 循环的正确方法是啥?

scala快速入门之基础篇-循环语法