F# - 对第二个元组项内的每个属性进行分组和应用函数

5

我有一个F#类列表,我正在使用属性来访问数据(我正在使用一个在C#中开发的库)。 我想按一个属性分组,然后对结果元组的第二个项目中的每个属性应用单独的函数。

示例:

let grouped = list  |> Seq.groupBy (fun x -> x.Year) //group by the year property. Results in Seq<int * seq<myClass>>
                    |> Seq.map (fun (a, b) -> (a, //How to map generic functions to each remaining property in the second tuple?  

希望这对某些人有意义。我的第二个元组项目是一个由groupBy生成的序列。MyClass中的每个剩余属性都需要应用不同的函数。过去,要对属性求和,我只需要执行以下操作:
|> Seq.map (fun (a, b) -> (a, b |> Seq.SumBy (fun x -> x.myProperty)))

我想使用 Seq.map 处理多个属性,实现类似于这样的功能。
非常感谢您的任何帮助, Richard
1个回答

12

你需要以某种方式指定要操作的属性 - 最简单的方法是创建一个读取这些属性的函数列表。假设你的类型是MyType,你可以写出类似这样的代码:


def get_properties(obj):
    return [obj.prop1, obj.prop2, obj.prop3]

my_obj = MyType()
properties_list = get_properties(my_obj)
let properties = [ (fun (x:MyType) -> x.MyProperty) ]

构建完组后,您可以使用List.map或F#列表推导式迭代所有properties中的属性,并计算values |> Seq.sumBy prop,其中values是该组,prop是当前属性:

let grouped = 
  list  
  |> Seq.groupBy (fun x -> x.Year) 
  |> Seq.map (fun (key, values) -> 
       (key, [for prop in properties -> values |> Seq.sumBy prop ])

如果需要使用除了Seq.sumBy之外的其他聚合函数,则可以构建一个聚合操作列表,并在其中运行需要的聚合操作(而不是属性列表)。

let properties = [ "MyPropSum", Seq.sumBy (fun (x:MyType) -> x.MyProperty);
                   "MyProp2Avg", Seq.averageBy (fun (x:MyType) -> x.MyProperty2) ]
为了使进一步的处理更加容易,我可能会构建一个字典来存储结果 - 这可以通过将包含名称-值对的列表传递给dict函数轻松完成:
let grouped = 
  list  
  |> Seq.groupBy (fun x -> x.Year) 
  |> Seq.map (fun (key, values) -> 
       (key, dict [for name, aggregate in properties -> name, aggregate values ])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接