F#:有效地从 List.scan 获取最后状态
F#: Efficiently get last state from List.scan
我 运行 List.scan 遍历了一个非常大的列表,以便计算 运行 总数。完成后,除了扫描输出之外,我还需要总数,以便不均匀地划分列表。 total是scan输出的最后一个状态,我真的很想避免为了得到最终状态而额外遍历列表。我能想到的唯一方法是传递一个可变引用来累加总数。有没有更好的方法来解决这个问题?
let l = <very large list of int64>
let runningTotal=List.scan (fun s x -> x+s) 0L l
let total= <last element of runningTotal- very inefficient>
doSomething total runningTotal
我认为实际上只访问列表中的最后一个元素确实是不可能的。也就是说,你说,你的清单非常大。当涉及到非常大的输入时,列表可能不是开始时的最佳数据结构。我想到的是,在这种情况下您当然可以使用数组而不是列表。数组也比列表更节省内存,因为列表将为每个元素创建一个引用,每个元素大约 12 个字节。而数组只有对第一个元素的引用。
如果数组适合您,那么这就是解决方案,因为您可以在没有 O(n) 开销的情况下访问数组的最后一个元素。
这是一种方法。由于我们可以定义 lambda 来做任何事情,只需让它始终将结果存储在 ref 单元格中即可。由于扫描从头到尾进行,结果将是最后一个值。
let last = ref 0L
let l = <very large list of int64>
let runningTotal=List.scan (fun s x ->let t = x+s;last=:t;t) 0L l
let total= !last
doSomething total runningTotal
在 F# 4.0 中,List.mapFold
变为 added,这很好地实现了这一点。
[1;2;3;4] |> List.mapFold (fun state elem -> let nxt = state + elem in (nxt,nxt)) 0
// > val it : int list * int = ([1; 3; 6; 10], 10)
List.last
也在 4.0 中添加,尽管它的性能仍然是 O(n)。如果您想从 F# 3.1 及更早版本的列表中提取最后一个元素,可以使用 fold
来完成,但同样,这是 O(n)。
let last lst =
lst |> List.fold (fun _ x -> x) Unchecked.defaultof<_>
@John 的解决方案可能是最快和最简单的。
我 运行 List.scan 遍历了一个非常大的列表,以便计算 运行 总数。完成后,除了扫描输出之外,我还需要总数,以便不均匀地划分列表。 total是scan输出的最后一个状态,我真的很想避免为了得到最终状态而额外遍历列表。我能想到的唯一方法是传递一个可变引用来累加总数。有没有更好的方法来解决这个问题?
let l = <very large list of int64>
let runningTotal=List.scan (fun s x -> x+s) 0L l
let total= <last element of runningTotal- very inefficient>
doSomething total runningTotal
我认为实际上只访问列表中的最后一个元素确实是不可能的。也就是说,你说,你的清单非常大。当涉及到非常大的输入时,列表可能不是开始时的最佳数据结构。我想到的是,在这种情况下您当然可以使用数组而不是列表。数组也比列表更节省内存,因为列表将为每个元素创建一个引用,每个元素大约 12 个字节。而数组只有对第一个元素的引用。
如果数组适合您,那么这就是解决方案,因为您可以在没有 O(n) 开销的情况下访问数组的最后一个元素。
这是一种方法。由于我们可以定义 lambda 来做任何事情,只需让它始终将结果存储在 ref 单元格中即可。由于扫描从头到尾进行,结果将是最后一个值。
let last = ref 0L
let l = <very large list of int64>
let runningTotal=List.scan (fun s x ->let t = x+s;last=:t;t) 0L l
let total= !last
doSomething total runningTotal
在 F# 4.0 中,List.mapFold
变为 added,这很好地实现了这一点。
[1;2;3;4] |> List.mapFold (fun state elem -> let nxt = state + elem in (nxt,nxt)) 0
// > val it : int list * int = ([1; 3; 6; 10], 10)
List.last
也在 4.0 中添加,尽管它的性能仍然是 O(n)。如果您想从 F# 3.1 及更早版本的列表中提取最后一个元素,可以使用 fold
来完成,但同样,这是 O(n)。
let last lst =
lst |> List.fold (fun _ x -> x) Unchecked.defaultof<_>
@John 的解决方案可能是最快和最简单的。