Need help translating C # to F #

I need help translating a custom extension for IndexOfAny for a string, as the existing infrastructure does not have IndexOfAny that matches string values. I have already translated mine. However, I have no idea how to exit the loop by the return value. Any idea how to get out of a loop or a better solution. Below is my translation.

WITH#

public static int IndexOfAnyCSharp(this string str, string[] anyOff) {
    if (str != null && anyOff != null)
        foreach (string value in anyOff) {
            int index = str.IndexOf(value);
            if (index > -1) return index;
        }
    return -1;
}

F #

[<Extension>]
static member public IndexOfAnyFSharp(str:string, anyOff:string[]) =
    match str <> null && anyOff <> null with
    | true ->
        let mutable index = -1
        for value in anyOff do
            if index = -1 then
                index <- str.IndexOf(value)
        index
    | false -> -1
+4
source share
2 answers

Seq.tryFind- your friend. The main building block will look like

let IndexOfAny (s: string, manyStrings: string seq) = 
    manyStrings
    |> Seq.map (fun m -> s.IndexOf m)
    |> Seq.tryFind (fun index -> index >= 0)

This will return Noneif nothing is found - it is more idiomatic F # than return -1: the compiler will make you think that nothing matches.

Update: You may prefer:

let IndexOfAny (s: string, manyStrings: string seq) = 
    manyStrings
    |> Seq.tryPick (fun m ->
        match s.IndexOf m with
        | -1 -> None
        | i -> Some i
    )
+7

Seq.tryFind Array.tryFind F #, , #. Seq, . .

F #, for. , , F # , .

. , , #. #, Result<int*int, Unit>. Result option, Result GC, .

IMO F # .

// If our function is callable from C# we can use active patterns as a neat way to protect our
//  F# code from null values
//  Functions that are only callable from F# code we don't need to protect as long as we protect
//  the entry points
let inline (|DefaultTo|) dv v = if System.Object.ReferenceEquals (v, null) then dv else v
let inline (|NotNull|) v      = if System.Object.ReferenceEquals (v, null) then raise (System.NullReferenceException ()) else v

let emptySet : string [] = [||]

let indexOfSet (DefaultTo "" str) (DefaultTo emptySet set) : Result<int*int, unit> =
    // In F# tail recursion is used as a more powerful looping construct
    //  F# suppports tail call elimination meaning under the hood this is
    //  implemented as an efficient loop
    //  Note: I pass str and set as argument in order to make F# doesn't
    //  create new lambda object that closes over them (reduces GC load)
    let rec loop (str : string) (set : string []) i =
        if i < set.Length then
            let index = str.IndexOf set.[i]
            if index = -1 then loop str set (i + 1)
            else Ok (i, index)
        else
          Error ()
    loop str set 0

printfn "%A" <| indexOfSet null null
printfn "%A" <| indexOfSet null     [| "abc"; "ab"; "a" |]
printfn "%A" <| indexOfSet ""       [| "abc"; "ab"; "a" |]
printfn "%A" <| indexOfSet "a"      [| "abc"; "ab"; "a" |]
printfn "%A" <| indexOfSet "ab"     [| "abc"; "ab"; "a" |]
printfn "%A" <| indexOfSet "abc"    [| "abc"; "ab"; "a" |]
printfn "%A" <| indexOfSet "da"     [| "abc"; "ab"; "a" |]
printfn "%A" <| indexOfSet "dab"    [| "abc"; "ab"; "a" |]
printfn "%A" <| indexOfSet "dabc"   [| "abc"; "ab"; "a" |]
+1

Source: https://habr.com/ru/post/1684363/


All Articles