csv - 如何使用 CSVProvider 加载具有不同结构的 csv?
问题描述
有任何想法吗?我当前的代码如下。
let rawdata csvfile
FinCsv.Load(data).Rows
|> Seq.filter (fun row -> row.Id <> "---")
|> Seq.filter (fun row -> row.Country <> "Honduras")
|> Seq.filter (fun row -> row.Tax <> 0)
|> Seq.groupBy (fun row -> row.Country)
|> Seq.averageBy (fun row -> row.Tax)
|> List.ofSeq
解决方案
静态解析类型参数的问题是语法很麻烦。这是一个例子:
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# 来说并不是特别惯用的。一种更惯用的方法是声明一个有区别的联合,但鉴于您发布的示例,它似乎没有必要。
推荐阅读
- android - 如何在 Jetpack compose 中制作 FlipCard 动画
- swift - 无法导入 EventKitUI。错误无法构建 Objective-C 模块
- c++ - 在 dll 中调用函数,同时在其中包含 dll/lib 文件
- coq - 为什么在相当简单的情况下无法进行案例分析
- python - 输出到终端和输出到文件得到不同的结果
- rest - 即使在 GET 请求中,我们也可以使用 SCIM 属性的“请求”可返回属性吗?
- routes - 如何在动态 nuxt.js 路由中的另一个 _slug 目录中使用 _slug?
- assembly - 包括另一个文件的程序集不起作用
- spring-security - 集成 Spring-session 和 Spring-security 会导致登录错误屏幕丢失 SPRING_SECURITY_LAST_EXCEPTION
- powerbi - 在 CAlculate 函数中使用 OR( || ) 不起作用