Если я правильно понимаю проблему, то вы, по сути, хотите вызвать функцию Seq.groupBy
. Проблема в том, что вы не совсем знаете лямбда-функцию, которую хотите передать в качестве аргумента при написании кода, потому что функция может варьироваться в зависимости от выбора ключей, которые следует использовать для группировки. Вот один из относительно простых способов сделать это ...
Мы создадим словарь функций, который даст нам функцию для чтения указанного свойства Trade
(в принципе это может быть построено автоматически, но, вероятно, его проще написать):
let keyfunctions : IDictionary<string, Trade -> obj> =
dict [ "TradeDate", (fun t -> box t.TradeDate);
"BrokerId", (fun t -> box t.BrokerId);
"MarketId", (fun t -> box t.MarketId); ]
Теперь, если мы хотим использовать несколько клавиш, нам нужен способ объединить две функции, которые дают нам части ключа, в одну функцию. Мы можем написать комбинатор, который принимает две функции и возвращает одну, которая создает кортеж в штучной упаковке в качестве ключа:
let combine f1 f2 = (fun t -> box (f1 t, f2 t))
Если у вас есть список строк, в котором указаны ваши ключи, то вам просто нужно выбрать функцию из словаря для каждой из клавиш и объединить их в одну функцию, используя combine
:
let grouping = [ "TradeDate"; "MarketId" ]
let func = grouping |> Seq.map (fun n -> keyfunctions.[n]) |> Seq.reduce combine
И теперь у вас есть функция, которую можно использовать в качестве аргумента для Seq.groupBy
:
trades |> Seq.groupBy func
Возможно, есть другие способы сделать это в F #, но я думаю, что это относительно простой подход, который может убедить вашего босса :-). Как примечание, вы могли бы написать, по существу, то же самое в C # 3.0, хотя это выглядело бы немного уродливее из-за более тяжелого синтаксиса ...
EDIT 1 : Хорошая особенность этого подхода в том, что вам не нужно использовать какие-либо отражения. Все работает как скомпилированный код, поэтому он должен быть довольно эффективным. Составленная функция просто вызывает несколько других функций (методы .NET) и упаковывает возвращаемые значения ...
РЕДАКТИРОВАТЬ 2 : Что касается порядка - этот подход будет работать (при сравнении кортежей сначала сравниваются первые элементы), но я не совсем уверен, в каком порядке агрегируются элементы при использовании Seq.reduce
, так что, может быть, этот пример работает наоборот ...