F# 中的排名函数
Ranking Function in F#
我写了一个排序数组的算法。
let rankFun array =
let arrayNew = List.toArray array
let arrayLength = Array.length arrayNew
let rankedArray = Array.create arrayLength 1.0
for i in 0 .. arrayLength - 2 do
for j in (i+1) .. arrayLength - 1 do
if arrayNew.[i] > arrayNew.[j] then
rankedArray.[i] <- rankedArray.[i] + 1.0
elif arrayNew.[i] < arrayNew.[j] then
rankedArray.[j] <- rankedArray.[j] + 1.0
else
rankedArray.[i] <- rankedArray.[i] + 0.0
rankedArray
我想问你,你对性能有什么看法?我使用了 for 循环,我想知道您是否认为还有比这更好的方法。在开始之前,我正在对数组进行排序,保留原始索引、排名,然后才将每个排名恢复到其原始位置,这在性能方面确实很糟糕。现在我得到了这个改进的版本并正在寻找一些反馈。有什么想法吗?
编辑:重复的元素应该有相同的等级。 ;)
非常感谢您。 :)
我假设 运行ks 可以从对输入进行排序中获取,因为您评论说该问题对重复项的行为是一个错误。令人惊讶的是,您描述的排序解决方案 运行 比问题中显示的代码慢。应该会快很多。
通过排序解决此问题的一种简单方法是从所有值构建一个有序集。 F# 中的集合始终有序且不包含重复项,因此它们可用于创建 运行king。
从集合中,创建一个从每个值到其在集合中的索引的映射(加一,以保留以 1 开头的 运行king)。这样,您可以查找每个值的 运行k 以填充输出数组。
let getRankings array =
let rankTable =
Set.ofArray array
|> Seq.mapi (fun i n -> n, i + 1)
|> Map.ofSeq
array |> Array.map (fun n -> rankTable.[n])
这需要一个数组,而不是一个列表,因为问题中的输入参数称为 array
。它还为 运行ks 使用整数,因为这是用于此目的的普通数据类型。
这比原来的算法快多了,因为所有操作至多为 O(n*log(n)),而问题中的嵌套 for 循环为 O(n^2)。 (另请参阅:Wikipedia on Big O notation。)对于仅 10000 个元素,基于排序的解决方案在我的计算机上的运行速度已经快了 100 多倍。
(顺便说一句,语句 else rankedArray.[i] <- rankedArray.[i] + 0.0
似乎什么也没做。除非你在用优化器做某种黑魔法,否则你可以删除它。)
我写了一个排序数组的算法。
let rankFun array =
let arrayNew = List.toArray array
let arrayLength = Array.length arrayNew
let rankedArray = Array.create arrayLength 1.0
for i in 0 .. arrayLength - 2 do
for j in (i+1) .. arrayLength - 1 do
if arrayNew.[i] > arrayNew.[j] then
rankedArray.[i] <- rankedArray.[i] + 1.0
elif arrayNew.[i] < arrayNew.[j] then
rankedArray.[j] <- rankedArray.[j] + 1.0
else
rankedArray.[i] <- rankedArray.[i] + 0.0
rankedArray
我想问你,你对性能有什么看法?我使用了 for 循环,我想知道您是否认为还有比这更好的方法。在开始之前,我正在对数组进行排序,保留原始索引、排名,然后才将每个排名恢复到其原始位置,这在性能方面确实很糟糕。现在我得到了这个改进的版本并正在寻找一些反馈。有什么想法吗?
编辑:重复的元素应该有相同的等级。 ;)
非常感谢您。 :)
我假设 运行ks 可以从对输入进行排序中获取,因为您评论说该问题对重复项的行为是一个错误。令人惊讶的是,您描述的排序解决方案 运行 比问题中显示的代码慢。应该会快很多。
通过排序解决此问题的一种简单方法是从所有值构建一个有序集。 F# 中的集合始终有序且不包含重复项,因此它们可用于创建 运行king。
从集合中,创建一个从每个值到其在集合中的索引的映射(加一,以保留以 1 开头的 运行king)。这样,您可以查找每个值的 运行k 以填充输出数组。
let getRankings array =
let rankTable =
Set.ofArray array
|> Seq.mapi (fun i n -> n, i + 1)
|> Map.ofSeq
array |> Array.map (fun n -> rankTable.[n])
这需要一个数组,而不是一个列表,因为问题中的输入参数称为 array
。它还为 运行ks 使用整数,因为这是用于此目的的普通数据类型。
这比原来的算法快多了,因为所有操作至多为 O(n*log(n)),而问题中的嵌套 for 循环为 O(n^2)。 (另请参阅:Wikipedia on Big O notation。)对于仅 10000 个元素,基于排序的解决方案在我的计算机上的运行速度已经快了 100 多倍。
(顺便说一句,语句 else rankedArray.[i] <- rankedArray.[i] + 0.0
似乎什么也没做。除非你在用优化器做某种黑魔法,否则你可以删除它。)