任何想法?我目前的代码如下。
z = sum(d['blue'].values())
答案 0 :(得分:4)
静态解析类型参数的问题是语法很麻烦。这是一个例子:
let inline snippet< ^T when ^T : (member Id : string)
and ^T : (member Country : string)
and ^T : (member Tax : float) >
xs =
xs
|> Seq.filter (fun row -> ( ^T : (member Id : string) row) <> "---")
|> Seq.filter (fun row -> ( ^T : (member Country : string) row) <> "South America")
|> Seq.filter (fun row -> ( ^T : (member Tax : float) row) <> 0.0)
|> Seq.groupBy (fun row -> ( ^T : (member Country : string) row))
|> Seq.map (fun (country, rows) -> country, (rows |> Seq.averageBy (fun row -> ( ^T : (member Tax : float) row))))
|> List.ofSeq
(我修改了averageBy调用,因此它比问题中的调用更有意义。)
您实际上可以让编译器推断出约束而不是明确地声明它们:
let inline snippet xs =
xs
|> Seq.filter (fun row -> ( ^T : (member Id : string) row) <> "---")
|> Seq.filter (fun row -> ( ^T : (member Country : string) row) <> "South America")
|> Seq.filter (fun row -> ( ^T : (member Tax : float) row) <> 0.0)
|> Seq.groupBy (fun row -> ( ^T : (member Country : string) row))
|> Seq.map (fun (country, rows) -> country, (rows |> Seq.averageBy (fun row -> ( ^T : (member Tax : float) row))))
|> List.ofSeq
作为替代方案,您可以要求调用者传递value-getter函数:
let snippet2 getId getCountry getTax xs =
xs
|> Seq.filter (fun row -> getId row <> "---")
|> Seq.filter (fun row -> getCountry row <> "South America")
|> Seq.filter (fun row -> getTax row <> 0.0)
|> Seq.groupBy (fun row -> getCountry row)
|> Seq.map (fun (country, rows) -> country, (rows |> Seq.averageBy (fun row -> getTax row))))
|> List.ofSeq
这使您可以稍微简化语法:
let snippet2 getId getCountry getTax xs =
xs
|> Seq.filter (getId >> (<>) "---")
|> Seq.filter (getCountry >> (<>) "South America")
|> Seq.filter (getTax >> (<>) 0.0)
|> Seq.groupBy getCountry
|> Seq.map (fun (country, rows) -> country, (rows |> Seq.averageBy getTax))
|> List.ofSeq
您可以使用部分应用声明函数的特定于类型的实例:
let snippetForCsvFile1 (xs : CsvFile1 seq) = xs |> snippet2 (fun r -> r.Id) (fun r -> r.Country) (fun r -> r.Tax)
然后你的开关看起来像这样:
let rawdata csvfile =
match csvfile with
| 1 -> snippetForCsvFile1 CsvFile1
| 2 -> snippetForCsvFile2 CsvFile2
| 3 -> snippetForCsvFile3 CsvFile3
| 4 -> snippetForCsvFile4 CsvFile4
| _ -> failwith "Not a File"
然后应该使用你的最后一个表达式:
let raw =
[ 1 .. 4]
|> List.collect rawdata
您的问题中的开关存在您在问题中未提及的问题:
let rawdata csvfile =
let data =
match csvfile with
| 1 -> CsvFile1
| 2 -> CsvFile2
| 3 -> CsvFile3
| 4 -> CsvFile4
| _ -> failwith "Not a File"
这里的问题是data
的绑定没有单一类型。您可以使用接口(或基类)使用面向对象的方法来实现这一点,但对于F#而言,这不是特别惯用的。一个更惯用的方法是宣布一个有区别的联盟,但是如果你发布它的例子似乎没有必要。