F# - GroupBy 并将函数应用于第二个元组项内的每个属性

问题描述 投票:0回答:1

我有一个 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 产生的 seq。 MyClass 中的每个剩余属性都需要应用不同的函数。在过去,为了总结财产,我刚刚做了类似的事情:

|> Seq.map (fun (a, b) -> (a, b |> Seq.SumBy (fun x -> x.myProperty)))

我想使用 Seq.map 对多个属性执行类似的操作

dictionary group-by f# sequence
1个回答
12
投票

您需要以某种方式指定要使用的属性 - 最简单的方法是创建读取属性的函数列表。假设你的类型是

MyType
,你可以这样写:

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

构建组后,您可以迭代

properties
中的所有属性(使用
List.map
或 F# 列表理解)并计算
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 ])
© www.soinside.com 2019 - 2024. All rights reserved.