Seq.map从一个列表填充另一个不同类型的列表?

时间:2014-02-23 20:24:51

标签: f# mapping sequence

此问题是对早期问题Preserving Field names across the F#/C# boundary

的跟进

由于F#类型提供程序遇到当前的限制(请参阅前面的问题),我想将类型提供程序生成的列表映射到我自己的记录列表,其中记录部分是

type inspection = {
    inspectionID : string;
    inspectorID : int;
    EstablishmentID : string;
    EstablishmentName : string;  // other members elided
}

我认为这样做的方法是使用Seq.map,但我不确定。 (回想一下,我正在做一个学习练习。)所以这就是我的尝试:

type restaurantCsv = CsvProvider<"C:\somepath\RestaurantRatings2013.csv",HasHeaders=true> 
// which generates a type, but it is an "erased" type, so member names do not propogate
//    over to C#.

type RawInspectionData(filename : string) = 
    member this.allData = restaurantCsv.Load(filename)  // works fine

    member this.allInspections = 
        this.allData.Data
            |> Seq.map(fun rcrd -> new inspection[{inspectionID = rcrd.InspectionID;}])

当然,完整的声明将其他成员名称作为检查的一部分,这里为了简洁而省略。有人向我指出 F#科学家的第43页,这就是为什么我认为这种格式与花括号一起使用。但是这会产生语法错误,“表达式中的意外符号'{'。预期',',']'或其他标记。”

但是,希望这个片段足以显示我想要做的事情,从Erased Type创建Generated Type。我怎么能做到这一点?

1 个答案:

答案 0 :(得分:3)

您的代码正朝着正确的方向发展。使用Seq.map(类似于LINQ中的Select)时,需要将原始序列的单个元素转换为新序列的单个元素。因此lambda函数只需要创建一个记录实例。

使用{ Field1 = value1; Field2 = value2; ... }构建记录,因此您需要:

type RawInspectionData(filename : string) = 
  let allData = restaurantCsv.Load(filename)  // works fine
  member this.allInspections = 
    allData.Data
    |> Seq.map(fun rcrd -> {inspectionID = rcrd.InspectionID}) 

我还将allData从成员更改为本地let定义(这使其成为类的私有字段)。我想你的原始代码new inspection[{...}]试图用元素创建一个单独的数组 - 创建一个你要编写的数组[| { Field = value; ... } |](并且编译器会为你推断出数组的类型)。但在这种情况下,不需要任何数组。