在Array.Fold操作的文件夹功能中,我想回顾任意数量的项目。
我能想出的唯一方法就是这样。
let aFolder (dataArray, curIdx, result) (dataItem) =
let N = numItemsToLookBack(result, dataItem)
let recentNitems = dataArray.[curIdx - N .. curIdx - 1]
let result = aCalc(result, dataItem, recentNitems )
dataArray, curIdx + 1, result
myDataArray |> Array.fold aFolder (myDataArray, 0, initResult)
如您所见,我将整个dataArray和index传递给文件夹函数以获取“recentNitems”。 但是这种方式允许文件夹功能不仅可以访问前面的数据,还可以访问以下数据。
有没有办法阻止这种期待的事情? 或者,无论这个期待的问题如何,是否有更好的(更多功能或更有效)的方式?
答案 0 :(得分:2)
如果你需要回顾任意数量的元素,那么直接使用Array.fold
可能不是最好的选择,因为该函数是为你可以逐个处理元素的场景而设计的。
在F#中使用直接访问数组没有任何问题 - 只要你不改变它们,你仍然在编写功能代码(因此,使用索引进行递归+直接访问可能适用于你的场景)。 / p>
正如Yin Zhu所指出的,你可以生成数组的数组(使用Seq.windowed
),但是创建一个O(n)个小数组可能是一个很大的开销。这是一个你也可以使用的更复杂的技巧:
我看到你需要调用aCalc
函数,只将数组的相关部分作为参数。您可以为数组创建一个简单的包装器,它只提供对数组相关部分的访问:
type ArraySlice<'a>(arr:'a[], from, max) =
member x.Item
with get(index) =
let index = index + from
if index > max || index < from then failwith "out of range"
arr.[index]
据我了解您的代码,您需要根据结果生成 lookback 项目的数量,因此您可能需要使用单fold
来编写此内容。可以大致这样做:
// If you write this using lambdas or local 'let' binding, the
// 'dataArray' value will be in scope, so you don't need to keep it as
// part of the state...
(dataArray, (0, initResult)) ||> Array.fold (fun (i, result) item ->
let n = numItemsToLookBack (result, item)
let recent = new ArraySlice<_>(dataArray, max 0 (i - n), i - 1)
// Note: modify aCalc, so that it takes 'ArraySlice'
let result = aCalc(result, item, recent)
i + 1, result)
答案 1 :(得分:1)
如果修复了numItermToLookBack,那么你可以使用Seq.windowed
:
let arr = [|1;2;3;4;5;6;7;|]
let warr = arr |> Seq.windowed 3 |> Seq.toArray
你得到:
val warr : int [] array =
[|[|1; 2; 3|]; [|2; 3; 4|]; [|3; 4; 5|]; [|4; 5; 6|]; [|5; 6; 7|]|]
如果数字不固定,我不知道如何更容易地做到这一点。
BTW,在你的代码中
let recentNitems = dataArray.[curIdx - n .. curIdx - 1]
并且在我的方法中,每次都会创建一个新的小数组,这可能会损害性能。