Вопрос

I have a an F# list of classes for which I am using properties to access data (i'm using a library developed in C#). I would like to group by one property then apply a separate function to each property in the second item of the resulting tuple.

Example:

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?  

Hopefully this will make sense to someone. My second tuple item is a seq resulting from the groupBy. Each remaining property in MyClass needs to have a different function applying to it. In the past to sum a property i have just done something like:

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

I'd like to do something like this using Seq.map for several properties.

Many Thanks for any help at all, Richard

Это было полезно?

Решение

You need to somehow specify the properties that you want to work with - the simplest way is to create a list of functions that read the properties. Assuming your type is MyType, you can write something like this:

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

After you construct groups, you can then iterate over all properties in properties (using List.map or F# list comprehension) and caculate values |> Seq.sumBy prop where values is the group and prop is the current property:

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

If you need to use other aggregation functions than Seq.sumBy, then you can build a list of aggregating operations that you need to run (instead of a list of properties).

let properties = [ "MyPropSum", Seq.sumBy (fun (x:MyType) -> x.MyProperty);
                   "MyProp2Avg", Seq.averageBy (fun (x:MyType) -> x.MyProperty2) ]

To make further processing easier, I would probably build a dictionary with the results - this can be easily done by passing the list with name-value pairs to the dict function:

let grouped = 
  list  
  |> Seq.groupBy (fun x -> x.Year) 
  |> Seq.map (fun (key, values) -> 
       (key, dict [for name, aggregate in properties -> name, aggregate values ])
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top