F#:生成字数统计摘要
F#: Generating a word count summary
我是编程新手,F# 是我的第一门 .NET 语言。
我想读取一个文本文件的内容,统计每个词出现的次数,然后return最常见的10个词和每个词出现的次数。
我的问题是:在 F# 中是否鼓励使用字典?如果我想使用字典,我该如何编写代码? (我浏览了 MSDN 上的字典 class,但我仍然对如何将值更新为键感到困惑。)我是否总是必须在函数式编程中求助于使用 Map?
My questions are: Is using a dictionary encouraged in F#?
在 F# 中使用字典很好,尽管它确实使用了可变性,因此并不常见。
How would I write the code if I wish to use a dictionary?
如果您阅读该文件,并且有一个以逗号分隔值的字符串,您可以
使用类似于以下内容的解析:
// 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)
我想说这个任务的一个明显选择是使用 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
相同,在最后一种情况下我们将运算符用作函数。
总的来说,倒数第二行的作用是根据对中第二个条目的负值(出现次数)对序列进行排序。
虽然其他答案没有任何问题,但我想指出,已经有一个专门的函数可以获取序列中唯一键的数量:Seq.countBy
。将 's and 的答案的相关部分放在一起:
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); ...]
我是编程新手,F# 是我的第一门 .NET 语言。
我想读取一个文本文件的内容,统计每个词出现的次数,然后return最常见的10个词和每个词出现的次数。
我的问题是:在 F# 中是否鼓励使用字典?如果我想使用字典,我该如何编写代码? (我浏览了 MSDN 上的字典 class,但我仍然对如何将值更新为键感到困惑。)我是否总是必须在函数式编程中求助于使用 Map?
My questions are: Is using a dictionary encouraged in F#?
在 F# 中使用字典很好,尽管它确实使用了可变性,因此并不常见。
How would I write the code if I wish to use a dictionary?
如果您阅读该文件,并且有一个以逗号分隔值的字符串,您可以 使用类似于以下内容的解析:
// 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)
我想说这个任务的一个明显选择是使用 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
相同,在最后一种情况下我们将运算符用作函数。
总的来说,倒数第二行的作用是根据对中第二个条目的负值(出现次数)对序列进行排序。
虽然其他答案没有任何问题,但我想指出,已经有一个专门的函数可以获取序列中唯一键的数量:Seq.countBy
。将
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); ...]