代码之家  ›  专栏  ›  技术社区  ›  Peter Booster

F中的函数“startsWithVowel”#

f#
  •  2
  • Peter Booster  · 技术社区  · 16 年前

    给定一个元音列表,我已经编写了函数 startsWithVowel 调查单词是否以元音开头。正如您所看到的,我使用异常作为控制流,这并不理想。如何更好地实现这一点?

    let vowel = ['a'; 'e'; 'i'; 'o'; 'u']
    
    let startsWithVowel(str :string) = 
        try
            List.findIndex (fun x -> x = str.[0]) vowel
            true
        with
            | :? System.Collections.Generic.KeyNotFoundException -> false
    

    7 回复  |  直到 16 年前
        1
  •  11
  •   Brandon Bodnar    16 年前

    尝试改用exists方法

    let vowel = ['a'; 'e'; 'i'; 'o'; 'u']
    
    let startsWithVowel(str :string) = List.exists (fun x -> x = str.[0]) vowel
    

        2
  •  7
  •   Dario    16 年前

    使用 sets

    let vowels = Set.ofList ['a'; 'e'; 'i'; 'o'; 'u']
    
    let startsWithVowel(str : string) = vowels |> Set.mem (str.[0])
    
        3
  •  7
  •   Juliet    16 年前

    另一种选择,, tryFindIndex 返回部分或无,而不是引发异常:

    > let vowel = ['A'; 'E'; 'I'; 'O'; 'U'; 'a'; 'e'; 'i'; 'o'; 'u']
    
    let startsWithVowel(str :string) = 
        match List.tryFindIndex (fun x -> x = str.[0]) vowel with
        | Some(_) -> true
        | None -> false;;
    
    val vowel : char list = ['A'; 'E'; 'I'; 'O'; 'U'; 'a'; 'e'; 'i'; 'o'; 'u']
    val startsWithVowel : string -> bool
    
    > startsWithVowel "Juliet";;
    val it : bool = false
    > startsWithVowel "Omaha";;
    val it : bool = true
    
        4
  •  6
  •   cfern    16 年前

    我对本文中提到的几种方法进行了基准测试(编辑:第6条)。

    1. List.exists方法(约0.75秒)
    2. 集合包含进近(~0.51秒)
    3. String.IndexOf(~0.25秒)
    4. 未编译的正则表达式(~5-6秒)
    5. 已编译的正则表达式(~1.0秒)
    6. 模式匹配(为什么我第一次忘记了这个?)(~0.17秒)

    测试代码:

    open System.Text.RegularExpressions
    
    let startsWithVowel1 =
        let vowels = ['a';'e';'i';'o';'u']
        fun (s:string) -> vowels |> List.exists (fun v -> s.[0] = v)
    
    let startsWithVowel2 =
        let vowels = ['a';'e';'i';'o';'u'] |> Set.ofList
        fun (s:string) -> Set.contains s.[0] vowels
    
    let startsWithVowel3 (s:string) = "aeiou".IndexOf(s.[0]) >= 0
    
    let startsWithVowel4 str = Regex.IsMatch(str, "^[aeiou]")
    
    let startsWithVowel5 = 
        let rex = new Regex("^[aeiou]",RegexOptions.Compiled)
        fun (s:string) -> rex.IsMatch(s)
    
    let startsWithVowel6 (s:string) =
        match s.[0] with
        | 'a' | 'e' | 'i' | 'o' | 'u' -> true
        | _ -> false  
    
    //5x10^5 random words
    let gibberish = 
        let R = new System.Random()
        let (word:byte[]) = Array.zeroCreate 5
        [for _ in 1..500000 -> 
            new string ([|for _ in 3..R.Next(4)+3 -> char (R.Next(26)+97)|])
        ]
    
    //f = startsWithVowelX, use #time in F# interactive for the timing
    let test f =
        for _ in 1..10 do
            gibberish |> List.filter f |> ignore
    

    编辑: 这个

    这套方法赢得了选美比赛。

        5
  •  4
  •   Brian    16 年前

    还请注意,许多异常引发函数具有非异常等价物,它们返回选项而不是引发-这些函数名称中通常有一个“try”前缀。

    http://msdn.microsoft.com/en-us/library/ee340224(VS.100).aspx

    另见

    http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!181.entry

        6
  •  2
  •   wethercotes    16 年前

    使用正则表达式:

    open System.Text.RegularExpressions
    
    let startsWithVowel str = Regex.IsMatch(str, "^[AEIOU]", RegexOptions.IgnoreCase)
    
        7
  •  0
  •   primodemus    16 年前
    let startsWithVowel (word:string) = 
        let vowels = ['a';'e';'i';'o';'u']
        List.exists (fun v -> v = word.[0]) vowels