【发布时间】:2014-03-05 05:00:53
【问题描述】:
给定一个数据集,例如一个可能如下所示的 CSV 文件:
x,y
1,2
1,5
2,1
2,2
1,1
...
我希望创建一个包含给定 x 的 y 的列表映射...结果可能如下所示:
{1:[2,5,1], 2:[1,2]}
在 python 中,这将是直接以命令的方式执行的......并且可能看起来有点像这样:
d = defaultdict(list)
for x,y in csv_data:
d[x].append(y)
您将如何使用 F# 中的函数式编程技术实现相同的目标? 是否有可能像给定的 python 示例一样,只使用函数式样式,做到简短、高效和简洁 (并且可读)?可变数据结构..?
注意:这不是一个家庭作业,只是我试图把我的头包裹在函数式编程上
编辑:我的结论基于迄今为止的答案
我尝试在一个相对较大的 csv 文件上计时每个提供的答案,只是为了感受一下性能。此外,我用命令式方法做了一个小测试:
let res = new Dictionary<string, List<string>>()
for row in l do
if (res.ContainsKey(fst row) = false) then
res.[fst row] <- new List<string>()
res.[fst row].Add(snd row)
命令式方法在 ~0.34 秒内完成。
我认为 Lee 提供的答案是最一般的 FP 答案,但运行时间约为 4 秒。
Daniel 给出的答案运行时间约为 1.55 秒。
最后 jbtule 给出的答案在 ~0.26 范围内运行。 (我觉得它击败了命令式方法非常有趣)
我使用'System.Diagnostics.Stopwatch()' 进行计时,代码在.Net 4.5 中作为F# 3.0 执行
EDIT2:修复了命令式 f# 代码中的愚蠢错误,并确保它使用与其他解决方案相同的列表
【问题讨论】:
-
在速度方面,它更多的是关于数据结构,而不是创建它的少量代码。
Map(平衡树)、Dictionary(可变哈希表)、Lookup(非可变哈希表),它们都有不同的特征,尤其是与您放入其中的数据大小有关。此外,您不应该只考虑创建时间,因为很可能会在更快的创建和更慢的值查找之间进行权衡。 -
我实际上假设 Maps 在 FP 中的哈希表..很高兴知道它们实际上是平衡树..所以显然 Maps 必须具有较慢的查找时间,O(log n) 或类似的东西。
-
您可以进一步改进命令式版本:dotnetfiddle.net/T3DUDV
标签: f#