2009-11-23 3 views
2

Учитывая список гласных, я написал функцию startsWithVowel, чтобы исследовать, начинается ли слово с гласного. Как вы можете видеть, я использую исключение как controlflow, и это не идеально. Как это реализовать лучше?Функция 'startsWithVowel' в F #

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 

UPDATE: ТЕ всем: раз я переживаю: не стесняйтесь задать Newbee вопрос. Я вижу много очень полезных замечаний, держать их :-)

ответ

7

Использование sets для эффективного поиска

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

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

Хорошая идея. Я использовал List в своем ответе только потому, что это то, с чего мы начали. Набор имеет более близкое значение для намерения гласных. Что касается производительности, тем не менее, meh, так как коллекция настолько мала. –

11

попробуйте использовать метод существует вместо

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

let startsWithVowel(str :string) = List.exists (fun x -> x = str.[0]) vowel 

существует возвращает истину, если какой-либо элемент в списке возвращает истину предиката и ложь в противном случае.

+0

Очень очень новичок, чтобы пропустить это, tx! – Peter

4

Отметим также, что ряд исключений метания функций имеют не-исключения эквиваленты, которые возвращают параметр, а не бросать - это, как правило, имеют префикс «попробовать» в имени функции ,

List.tryFindIndex:

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

Смотри также

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

+0

Tx, я понял, что через C# (где используются bool и out par) – Peter

7

Еще одна альтернатива, 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 
+0

Почему никто не использует наборы? – Dario

+5

Потому что ... наборы УБИЛИ МОЙ ОТЕЦ! – Juliet

2

Использование регулярных выражений:

open System.Text.RegularExpressions 

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

Почти чистый CLR, но в любом случае, еще одно ценное решение – Peter

6

Я проверил несколько подходов, упомянутых в этой теме (Edit: added nr. 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 секунды)
?

Я заполнил список 500000 случайных слов и отфильтровал его через различные функции startWithVowel, повторяющиеся 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 

Мой скромный вывод: EDIT: императив IndexOf F матч # модель выигрывает соревнование скорости.

Подход Set.contains выигрывает конкурс красоты.

+1

+1 очень интересно – Peter

+0

IMO, соответствие шаблону выигрывает конкурс красоты. – Daniel

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