映射在视图上的函数列表 - 视图是不是被多次遍历?
Posted
技术标签:
【中文标题】映射在视图上的函数列表 - 视图是不是被多次遍历?【英文标题】:List of functions mapped on view - is the view traversed more than once?映射在视图上的函数列表 - 视图是否被多次遍历? 【发布时间】:2013-11-15 12:48:06 【问题描述】:我正试图围绕如何在 Scala 中使用视图。我有以下示例代码:
class Square extends (Seq[Int] => Int)
def apply(x: Seq[Int]) = x.reduce(_ * _)
class Sum extends (Seq[Int] => Int)
def apply(x: Seq[Int]) = x.reduce(_ + _)
val functionList = List(new Square, new Sum)
val list = List(1, 2, 3, 4, 5, 6)
val view = list.view
functionList.map(f => f(view))
我的问题是:
-
上例中应用地图时,列表会被遍历一次还是两次?
如果遍历不止一次,是否有任何其他设计模式可以让我定义函数集合并映射到其他集合,同时只遍历第二个集合一次?
【问题讨论】:
【参考方案1】:列表被遍历了两次。您实际上要做的是首先使用Square
函数并在所有元素上应用reduce
。接下来,Sum
函数还将对所有元素应用reduce
。
视图将集合变成惰性集合。这意味着如果您有多个转换,它们只会在需要时应用。在这种情况下,我认为这对您的解决方案没有任何影响,因为您正在应用对整个集合进行计算的函数(这意味着需要对它们进行评估以获得结果)。有关何时使用视图的答案,请参阅 this question。
在这种情况下,遍历第二个集合并不容易。您有两个函数在整个列表中执行 reduce
,这意味着每个函数都需要一个 单独的累加器 并具有单独的结果。如果你只想遍历你的元素列表一次,你需要稍微改变你的逻辑。您需要定义关于如何组合两个元素的操作,而不是定义对整个列表的操作。这是我想出的:
val functionListWithInitialValues = List(
((a: Int, b: Int) => a * b, 1), //This is a Tuple that defines how to combine two calculations and what the initial value is.
((a: Int, b: Int) => a + b, 0)
)
val results = list.foldLeft(functionListWithInitialValues)
case (accumulators, next) => // foldLeft gives us the previous results
// (which is essentailly a Tuple(function, value)),
// and the next element, to combine with the previous result.
// Now let's go through our functions and apply the functions on the accumulator and the next element
accumulators.map
case (function, previousResult) =>
(function, function(previousResult, next))
results.map case (function, result) => println(result)
这个解决方案只会遍历你的元素一次,对累加器和下一个元素应用组合函数。
【讨论】:
【参考方案2】:不确定您在说什么列表。
您正在将映射应用于实际的严格列表,因此 functionList 将被遍历一次,并且将“f”应用于视图将减少 functionList 中每个函数的 List[Int]。
如果你想懒惰地应用你的修改器,那么 functionList 应该是一个视图,这样 'map' 就不严格了。
【讨论】:
以上是关于映射在视图上的函数列表 - 视图是不是被多次遍历?的主要内容,如果未能解决你的问题,请参考以下文章