F#中的函数'startsWithVowel'

时间:2009-11-23 17:10:27

标签: f#

给定一个元音列表,我编写了函数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

更新:tx to all:我再一次体验:毫不犹豫地问一个新问题。我看到很多非常有用的评论,让他们来吧:-)

7 个答案:

答案 0 :(得分:11)

尝试使用exists方法

let vowel = ['a'; 'e'; 'i'; 'o'; 'u']

let startsWithVowel(str :string) = List.exists (fun x -> x = str.[0]) vowel
如果列表中的任何元素对谓词返回true,则

exists返回true,否则返回false。

答案 1 :(得分:7)

使用sets进行有效查询

let vowels = Set.ofList ['a'; 'e'; 'i'; 'o'; 'u']

let startsWithVowel(str : string) = vowels |> Set.mem (str.[0])

答案 2 :(得分:7)

另一种选择,tryFindIndex返回Some或None而不是抛出异常:

> 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

答案 3 :(得分:6)

我对此线程中提到的一些方法进行了基准测试(编辑:添加了第6页)。

  1. List.exists方法(~0.75秒)
  2. Set.contains方法(~0.51秒)
  3. String.IndexOf(~0.25秒)
  4. 未编译的正则表达式(约5 - 6秒)
  5. 编译的正则表达式(~1.0秒)
  6. 模式匹配(为什么我第一次忘记这个?)(~0.17秒)
  7. 我填写了一个包含500000个随机单词的列表,并通过各种startsWithVowel函数对其进行过滤,重复10次。

    测试代码:

    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
    

    我的拙见: 编辑: 命令式IndexOf F#模式匹配赢得速度竞赛。

    Set.contains方法赢得选美比赛。

答案 4 :(得分:4)

另请注意,许多抛出异常的函数都具有返回选项而非抛出的非异常等效项 - 这些函数通常在函数名称中包含'try'前缀。

List.tryFindIndex:

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

另见

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

答案 5 :(得分:2)

使用正则表达式:

open System.Text.RegularExpressions

let startsWithVowel str = Regex.IsMatch(str, "^[AEIOU]", RegexOptions.IgnoreCase)

答案 6 :(得分:0)

let startsWithVowel (word:string) = 
    let vowels = ['a';'e';'i';'o';'u']
    List.exists (fun v -> v = word.[0]) vowels
相关问题