[英]Dictionary comprehensions(?) in F# (converting from C#)
好,所以,我剛開始學習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
]
]
此代碼有兩個問題:
我該如何改善? 我做錯了嗎?
我認為更實用的方法是:
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。
這是您眼前一個問題的答案-但老實說,我可能會選擇一個單獨的函數來查找和拆分重復項,並使用一個單獨的函數來構建地圖而無需照顧潛在的重復項-即使那意味着多個傳遞數據。
根據您的要求,您所擁有的可能是最好的。 您可以使用模式匹配來加緊代碼。
let dataDict = Dictionary<_,Dictionary<_,_>>()
for d in data do
match dataDict.TryGetValue(d.Id) with
| true, m when m.ContainsKey(d.Analysis) ->
(d.Id, d.Analysis)
||> sprintf "Id '%s' has more than one analysis of type '%s', rows will be ignored"
|> logger.Warn
| true, m ->
m.Add(d.Analysis, d)
| _ ->
let m = Dictionary()
m.Add(d.Analysis, d)
dataDict.Add(d.Id, m)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.