序列和运行查询示例

时间:2011-03-10 23:10:44

标签: search f# design-patterns sequence repeat

我想获得一些关于如何使用F#/函数式编程来搜索列表中重复值的指针和/或示例代码。

考虑以下用例: 给定每个日期的列表/数组/日期序列和最高温度,我想提取出连续n天的临时值大于给定阈值的初始日期。

这种类型的查询的另一个例子是在股票价格历史表/列表中搜索超过给定阈值的价格,该阈值在指定的时间间隔内保持(例如至少30天)。 在这种情况下,我正在寻找首次超过阈值的初始日期。

TIA

2 个答案:

答案 0 :(得分:1)

我可能会从一个效率较低但优雅的功能解决方案开始,该解决方案使用Seq.windowed函数(将序列转换为指定大小的连续组的序列):

source
// Create groups of specified size
|> Seq.windowed requiredLength
// Add starting indices to the sequence
|> Seq.mapi (fun i v -> i, v)
// Find all groups that contain only numbers larger than treshold
|> Seq.filter (fun (i, v) -> v |> Seq.forall ((<) treshold))
// Get indices of such groups
|> Seq.map fst

这会返回所有这些组的索引,因此如果有多个重叠组(即匹配条件的较大序列),那么您将获得所有起始索引。您可能只是从结果中过滤连续数字以仅获取组的第一个索引(使用Seq.fold)。

要获得更高效的版本,您需要编写一个遍历数组或列表的递归函数。当您在阈值上找到最后一个值时,您可能需要记住(在函数参数中)。 (这与命令式循环基本相同,除了你使用递归函数并在参数中保持状态)。

答案 1 :(得分:1)

虽然我喜欢Tomas代码的简洁性,但我不禁认为他所暗示的更有效的版本在这里是非常强制的,特别是如果实际比较逻辑比简单的整数比较更昂贵。我提交以下抽象:

let findWindowBeginnings predicate minWindowSize data =
    if minWindowSize < 2 then
        invalidArg "minWindowSize" "minWindowSize must be greater than 1"

    ((None, []), data)
    ||> Seq.fold (fun (window, acc) x ->
        if predicate x then
            match window with
            | Some (start, size) -> let size' = size + 1
                                    let acc' = if size' = minWindowSize
                                               then start::acc
                                               else acc
                                    Some (start, size'), acc'
            | _                  -> Some (x, 1), acc
        else None, acc)
    |> snd
    |> List.rev

日期+温度元组序列的用例如下:

let findHeatwaveBeginnings tempThreshold consecutiveDays data =
    (consecutiveDays, data)
    ||> findWindowBeginnings (snd >> (<) tempThreshold)
    // alternatively, if you're not a fan of point-free style code:
    //  findWindowBeginnings (fun (_, maxTemp) -> maxTemp > tempThreshold)
    |> List.map fst

因为findWindowBeginningsSeq.fold驱动,所以它当然会与数组和列表一起使用。此外,findWindowBeginnings对于正在检查的数据类型是完全不可知的,因为您传入的谓词执行数据自省,谓词当然可以处理您喜欢的任何数据类型(元组,记录,适当的类/结构,等等。)。唯一的要求是输入数据按逻辑排序。

F#Snippets链接:http://fssnip.net/3u