F#Array.tryFindIndex从索引开始搜索

时间:2019-05-23 07:45:36

标签: f#

我想知道是否有一个便宜的(性能明智的)选项来搜索从索引开始满足特定条件的数组元素的索引?

Array.tryFindIndex方法没有参数startIndex。我可以做Array.skip(n)然后在那里搜索,但是创建一个仅用于搜索的数组似乎很昂贵。我该怎么做?

我看着List也没有那个参数。 我需要在...期间使用吗?有更好的方法吗?

3 个答案:

答案 0 :(得分:5)

基础库试图为您提供方便的功能,但是它们可能无法预期所有用例。如果需要的话,写自己的东西没错:

module Array =
    let tryFindIndexFrom i p (a : _ []) =
        let rec loop k =
            if k >= a.Length then None
            elif p a.[k] then Some k
            else loop (k + 1)
        if i < 0 then None else loop i

编辑p是测试数组元素的谓词。 tryFindIndexFrom具有与tryFindIndex相同的签名,但是添加了起始索引作为第一个参数。

编辑2:添加了针对k < 0的安全使用测试。

编辑3:由于k < 0的测试仅需要检查一次,因此已从循环中移出。

答案 1 :(得分:2)

这是一种使用数组索引的惰性序列进行操作的方法:

let input = [| 'a' .. 'z' |]

seq { 4 .. input.Length - 1 }
|> Seq.tryFind (fun i -> input |> Array.tryItem i = Some 'x')

如果您认为有必要,我将把它归纳为一个辅助函数。

当前表单的好处是它非常灵活。您可以轻松更改最大索引,也可以向后搜索,例如seq { input.Length - 1 .. -1 .. 4 }

答案 2 :(得分:2)

遵循您的直觉。考虑到Array.skip,但要注意分配第二个数组的明显浪费,您可以将其进一步进行,并推广到懒惰求值的Seq.skip,将其与标准Seq.tryFindIndex函数组合并添加偏移量(如果适用)。

let tryFindIndexMin n p =
    Seq.skip n
    >> Seq.tryFindIndex p
    >> Option.map ((+) n)
// val tryFindIndexMin : n:int -> p:('a -> bool) -> (seq<'a> -> int option)

[ for i in 0..3 ->
    [|"a"; "b"; "a"; "b"|]
    |> tryFindIndexMin i ((=) "a") ]
// val it : int option list = [Some 0; Some 2; Some 2; null]