2015-03-20 4 views
0

Я новичок в программировании, а F # - это мой первый язык .NET.F #: Сгенерируйте подсчет количества слов

Я хотел бы прочитать содержимое текстового файла, подсчитать количество вхождений каждого слова, а затем вернуть 10 наиболее распространенных слов и количество раз, когда каждый из них появляется.

Мои вопросы: Использует ли словарь, рекомендованный в F #? Как написать код, если я хочу использовать словарь? (Я просматривал класс Dictionary в MSDN, но я все еще озадачен тем, как я могу обновить значение до ключа.) Всегда ли приходится прибегать к использованию Map в функциональном программировании?

ответ

3

Хотя нет ничего плохого в других ответах, я хотел бы указать, что уже существует специализированная функция для получения количества уникальных ключей в последовательности: Seq.countBy. Сантехнические соответствующие части Reed-х и torbonde 's ответы вместе:

let countWordsTopTen (s : string) = 
    s.Split([|','|]) 
    |> Seq.countBy (fun s -> s.Trim()) 
    |> Seq.sortBy (snd >> (~-)) 
    |> Seq.truncate 10 

"one, two, one, three, four, one, two, four, five" 
|> countWordsTopTen 
|> printfn "%A" // seq [("one", 3); ("two", 2); ("four", 2); ("three", 1); ...] 
3

Мои вопросы: Использует ли словарь, рекомендованный в F #?

Использование словаря отлично от F #, хотя оно использует изменчивость, поэтому оно не так распространено.

Как написать код, если я хочу использовать словарь?

Если вы читаете файл, и есть строка с разделителями-запятыми, можно разобрать используя что-то похожее на:

// Just an example of input - this would come from your file... 
let strings = "one, two, one, three, four, one, two, four, five" 
let words = 
    strings.Split([|','|]) 
    |> Array.map (fun s -> s.Trim()) 

let dict = Dictionary<_,_>() 
words 
|> Array.iter (fun w -> 
    match dict.TryGetValue w with 
    | true, v -> dict.[w] <- v + 1 
    | false, _ -> dict.[w] <- 1) 

// Creates a sequence of tuples, with (word,count) in order 
let topTen = 
    dict 
    |> Seq.sortBy (fun kvp -> -kvp.Value) 
    |> Seq.truncate 10 
    |> Seq.map (fun kvp -> kvp.Key, kvp.Value) 
+0

спасибо, Рид. У меня есть следующий вопрос: в чем разница между Seq.take и Seq.truncate? Когда я должен использовать их каждый? –

+2

@MY_G Seq.take не удастся, если в коллекции будет меньше 10 элементов - усечение всегда будет успешным. (В приведенном выше примере seq.take не удался, так как у меня не было> 10 элементов;)) –

2

Я бы сказал, очевидный выбор для решения этой задачи является использование Seq модуль, который действительно является одним из основных рабочих лошадей в F #. Как сказал Рид, использование словаря не так распространено, так как оно изменено. Последовательности, с другой стороны, являются неизменными. Пример того, как сделать это с помощью последовательности является

let strings = "one, two, one, three, four, one, two, four, five" 
let words = 
    strings.Split([|','|]) 
    |> Array.map (fun s -> s.Trim()) 

let topTen = 
    words 
    |> Seq.groupBy id 
    |> Seq.map (fun (w, ws) -> (w, Seq.length ws)) 
    |> Seq.sortBy (snd >> (~-)) 
    |> Seq.truncate 10 

Я думаю, что код говорит довольно много для себя, хотя, может быть, второй последней строки требует краткого объяснения: snd -функции дает вторую позицию в паре (т.е. snd (a,b) - b), >> - оператор функциональной композиции (то есть (f >> g) a - это то же, что и g (f a)), а ~- - унарный оператор минус. Обратите внимание, что операторы являются, по существу, функциями, но при использовании (и объявлении) их в качестве функций вы должны обернуть их в круглые скобки. То есть -3 совпадает с (~-) 3, где в последнем случае мы использовали оператор как функцию.

Всего, что делает вторая последняя строка, сортирует последовательность по отрицательному значению второй записи в паре (количество вхождений).

+0

В более новых версиях F # это можно вычислить, используя 'Seq.countBy' – torbonde

Смежные вопросы