c# - F# 中的字典推导式(?)(从 C# 转换)

标签 c# f# functional-programming dictionary-comprehension

好吧,我刚刚开始学习 F#。我在大学等方面接触过一些函数式语言,但对于使用 F# 等语言进行现实世界编程,我仍然很陌生。

我每天都使用 C# 工作,但今天我有机会花一些时间研究公司的代码库,并从 F# 的角度来看待它。我决定尝试用 F# 重写一些 C# 代码,以在现实的业务环境中感受该语言。

以下是我努力翻译的一些 C# 代码的释义:

// MyData is a class with properties Id, Analysis, and some other relevant properties
// Each pair of (Id, Analysis) is (should be) distinct
IEnumerable<MyData> data = // fetch from DB...

// dataDict[id[analysis]] = MyData object (or "row") from DB
var dataDict = new Dictionary<String, Dictionary<String, MyData>> ();
foreach(var d in data)
{
    if(!dataDict.ContainsKey(d.Id))
        dataDict.Add(d.Id, new Dictionary<string, MyData>());

    if (dataDict[d.Id].ContainsKey(d.Analysis))
    {
        logger.Warn(String.Format("Id '{0}' has more than one analysis of type '{1}', 
            rows will be ignored", d.Id, d.Analysis));
    }
    else
    {
        dataDict[d.Id].Add(d.Analysis, d);
    }
} 

我尝试以“函数式”方式重写循环,得到了以下代码,但我感觉不太好。

let dataDict = 
      dict [ 
        for d in data 
          |> Seq.distinctBy(fun d -> d.Id) -> d.Id, 
             dict [                                                                                                   
                 for x in data |> Seq.filter(fun a -> a.Id = d.Id) -> x.Analysis, x
             ]
      ]

此代码有几个问题:

  • 如果出现重复的(Id、分析)对,它不会记录警告,甚至更糟
  • 我使用 for 和 Seq.filter 运行数据(至少)两次。

我该如何改进?我做错了吗?

最佳答案

我认为更实用的方法是:

let intoMap (data: seq<MyData>) = 
    Seq.fold (fun (datamap, dups) (data: MyData) -> 
        match datamap |> Map.tryFind data.Id with
        | Some submap when submap |> Map.containsKey data.Analysis -> 
            datamap, data :: dups
        | Some submap ->
            let ext = Map.add data.Analysis data submap
            (Map.add data.Id ext datamap), dups
        | None ->
            let submap = Map.ofArray [| (data.Analysis, data) |]
            (Map.add data.Id submap datamap), dups
        ) (Map.empty, List.empty) data

这是数据的折叠,因此它遍历序列一次。它还更实用,因为它没有副作用 - 不是记录重复项,而是收集它们并将其作为输出的一部分。稍后您可以对它们做任何您喜欢的事情。

此外,我使用不可变的 Map 而不是 Dictionary - 我发现 Dictionary 是 F# 代码中的一种代码味道。它提供的可变性在一些更深奥的场景中有其用途,但为了实际保存和传递数据,我会专门使用 Map。

这就是您直接问题的答案 - 但说实话,我可能会选择一个单独的函数来查找和拆分重复项,以及一个单独的函数来构建 map 而不关心潜在的重复项 -即使这意味着多次传递数据。

关于c# - F# 中的字典推导式(?)(从 C# 转换),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31081158/

相关文章:

f# - Hello world 不会用 "The value or constructor is not defined"编译

c# - 是否可以在我的应用程序中添加数据源连接向导?

c# - 以斜线为背景的形状

c# - 如何注销和注册等待事件处理程序?

f# - 从 WebSharper 访问 JavaScript 的 this

c# - 函数式编程对覆盖的回答是什么?

compiler-construction - F#中的属性语法系统

ruby-on-rails - 如何使用 Shoulda 正确测试此 Controller 操作?

clojure - 为什么不返回值的 Clojure 函数返回 nil?

c# - 在测试初始化​​方法中模拟 HttpContext.Current