我试图找出何时使用f#以及何时使用c#。我有能源交易的实际问题。电力合约报价为,交货开始,交货结束,关税,交易量。一个例子是,100MW Cal14 Offpeak,所以从2014年1月1日到2014年12月31日,如果工作时间在一周的20到8(夜间)或周末的所有时间,合同每小时可以提供100MW - 总计约5500小时。高峰合同在工作日提供8-20个,而Base提供所有小时数。
如果您有这些合约的投资组合,您希望将它们汇总为每小时位置向量。到目前为止我的代码在这里:
合同数据示例(包含Excel格式的日期):
let data = [(41275., 41639., "Base", 10.); (41275., 41639., "Base", 60.); (41275., 41639., "Peak", 20.); (41275.,41639.,"Offpeak",30.); (41275.,41364.,"Peak",40.); (41275.,41364.,"Peak",70.); (41275.,41364.,"Offpeak", 50.)]
汇总相同合同的功能:
let group_fold keys value fold acc seq =
seq |> Seq.groupBy keys
|> Seq.map (fun ((key1, key2, key3), seq) ->
(key1, key2, key3, seq |> Seq.map value |> Seq.fold fold acc))
let aggrTrades data =
data |> group_fold (fun (k1, k2, k3, _) -> k1, k2, k3) (fun (_, _, _, v) -> v) (+) 0.0
识别峰值和非峰值时间的功能:
let poindicator dts =
let newdts = DateTime.FromOADate dts
// Match on day of week and hour properties of the date time
match newdts.DayOfWeek, newdts.Hour with
// For weekend, return false
| DayOfWeek.Saturday, _ | DayOfWeek.Sunday, _ -> false
// For working hours, return true
| _, h when h >= 8 && h < 20 -> true
// For non-working weekday hours, return false
| _ -> false
最后一个函数将它们放在一起并创建一个小时向量(std =每小时向量的开始日期和edd =结束日期):
let hourlyvec data std edd =
let aggrdata = aggrTrades data
let dtsvec = [std.. 1./24. .. edd]
let nrhrs = dtsvec |> Seq.length
let mutable res = Seq.init nrhrs (fun i -> 0.0)
for i=0 to res |> Seq.length do
for (a, b, c, d) in aggrdata do
match a , b with
| e, f when e <= dtsvec.[i] && f >= dtsvec.[i] ->
match c with
| "Base" -> res.[i] <- res.[i] + d
| "Peak" when poindicator (DateTime.FromOADate dtsvec.[i]) -> res.[i] <- res.[i] + d
| "Offpeak" when not poindicator (DateTime.FromOADate dtsvec.[i]) -> res.[i] <- res.[i] + d
| _ -> failwith "Not recognized tarif"
|_ -> failwith "Not in period tarif"
dtsvec, res
这与FS0039失败:字段,构造函数或成员'Item'未定义,似乎也不喜欢嵌套的伪指标函数
任何指针都会非常感激吗?另外如果您认为这在c#中会更容易,请告诉我,我认为它是一个功能性问题所以我先去了f#。
答案 0 :(得分:2)
问题出在这里
match a , b with
| e, f when e <= dtsvec.[i] && f >= dtsvec.[i] -> ...
如果不满足条件,您将收到匹配失败异常,编译器会正确发出警告。
这里永远不会有效
match _, _, c, _ with
| "Base" -> res.[i] <- res.[i] + d
| "Peak" when poindicator DateTime.FromOADate dtsvec.[i] -> res.[i] <- res.[i] + d
| "Offpeak" when not poindic DateTime.FromOADate dtsvec.[i] -> res.[i] <- res.[i] + d
| _ -> failwith "Not recognized tarif"
因为您只能将_
放在|
之后不在match ... with
答案 1 :(得分:0)
我希望你能将这个问题重新发布到Code Review StackExchange,但是既然你没有,我会在这里发布我的简化版代码,以防OP或未来的访问者发现它有用:
let group_fold keys valueExtractor folder state seq =
seq
|> Seq.groupBy keys
|> Seq.map (fun ((key1, key2, key3), seq) ->
let finalState =
(state, seq)
||> Seq.fold (fun state v ->
let mappedValue = valueExtractor v
folder state mappedValue)
key1, key2, key3, finalState)
let poindicator dts =
let newdts = DateTime.FromOADate dts
// Match on day of week and hour properties of the date time
// For weekend, return false
newdts.DayOfWeek <> DayOfWeek.Saturday
&& newdts.DayOfWeek <> DayOfWeek.Sunday
// For working hours, return true
// For non-working weekday hours, return false
&& newdts.Hour >= 8
&& newdts.Hour < 20
let aggrTrades data =
data |> group_fold (fun (k1, k2, k3, _) -> k1, k2, k3) (fun (_, _, _, v) -> v) (+) 0.0
let hourlyvec data std edd =
let dtsvec = [|std.. 1./24. .. edd|]
let res =
let nrhrs = Array.length dtsvec
let aggrdata = aggrTrades data
Array.init nrhrs <| fun i ->
(0.0, aggrdata)
||> Seq.fold (fun periodValue (a, b, c, d) ->
match a, b with
| e, f when e <= dtsvec.[i] && f >= dtsvec.[i] ->
match c with
| "Base" ->
periodValue + d
| "Peak" when poindicator dtsvec.[i] ->
periodValue + d
| "Offpeak" when not (poindicator dtsvec.[i]) ->
periodValue + d
| _ ->
failwith "Not in Tarif"
|_ ->
failwith "Not in period")
dtsvec, res