是否有等效于 Python 的 Counter 集合的 F#?

jsm*_*000 2 python f# counter

希望将一些 Python 代码移植到 F#。我是两种语言的新手。Python 代码使用“Counter”集合,“其中元素存储为字典键,它们的计数存储为字典值”。以 Python 为例:

cnt = Counter()

for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']
   cnt[word] += 1

cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>> # Tally occurrences of words in a list
>> cnt = Counter()

>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:

>> ... cnt[word] += 1

>> cnt

>> Counter({'blue': 3, 'red': 2, 'green': 1})
Run Code Online (Sandbox Code Playgroud)

是否有等效于 Python 的 Counter 集合的 F#?

Aar*_*ach 5

在 F# 中,诸如此类的状态突变cnt[word] += 1是可能的,但通常会避免。相反,计算是通过使用高阶函数来描述操作的意图来表达的,而不是使用命令式命令来描述机制。在这种情况下,典型的 F# 解决方案可能如下所示:

let counts =
    ["red"; "blue"; "red"; "green"; "blue"; "blue"]
    |> List.groupBy id
    |> Map.ofList
    |> Map.map (fun _ words -> words |> List.length)
Run Code Online (Sandbox Code Playgroud)

在这里,我们采用相同的单词列表,然后使用List.groupByto 创建列表列表,并将id函数传递给它,说明我们要按值本身(列表中的单词)进行分组。单词列表实际上是 的第二个参数List.groupBy,但我们使用|>("pipe-forward") 运算符将前面的值作为最后一个参数传递给下一个函数。这很有用,因为它允许我们将操作链接在一起,正如我们在下一行中看到的,我们获取 返回的列表列表List.groupBy并将其传递给Map.ofList,这给了我们一个Map<string, string list>.

Map类允许我们通过一键查找做一样Counter的类型。然后我们通过管道将into的结果转换Map<string, string list>Map<string, int>带有每个单词计数的a ,这使我们可以传递一个函数,将映射中的值从一种类型转换为另一种类型。在这种情况下,我们希望将值从 a 转换为 an ,因此我们取(我们将其称为“单词”)并将其传递给以获取计数。函数参数 for有两个参数,键和值,但我们只对值感兴趣,所以我通过调用它忽略了键参数。这给了我们一个包含单词作为键和该单词在列表中的计数作为值的 a :Map.ofListMap.mapstring listintstring listList.lengthMap.map_Map<string, int>

val counts : Map<string,int> = map [("blue", 3); ("green", 1); ("red", 2)]
Run Code Online (Sandbox Code Playgroud)

编辑

正如评论中提到的 kvb,F#List模块已经有一个countBy功能,可以将groupBy与结合起来List.length。这使得代码更加简单:

let counts =
    ["red"; "blue"; "red"; "green"; "blue"; "blue"]
    |> List.countBy id
    |> Map.ofList
Run Code Online (Sandbox Code Playgroud)

这给出了与上面相同的结果,因为我们获取string * int元组列表并将其通过管道传输到Map.ofList,以便我们获得映射(如 PythonCounter对象)的查找功能。

  • 尽管 `groupBy` 确实有效,但使用 `countBy` 会简化事情。您真正需要的是将 `countBy id` 的结果通过管道传输到 `Map` 中,然后就大功告成了。 (2认同)