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 的一个实例,它是现有列表的视图只包含满足谓词的元素。