F# group by more than one value and aggregate
F#. I have a list transactions
of the following type:
type Transaction(Debitor: string, Spend:float, Creditor:string) =
member this.Debitor = Debitor
member this.Spend = Spend
member this.Creditor = Creditor
I know how to group by one value. Say for example I want to group per property Debitor
, it's easy to use that property as the Key of the group:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> ts.Debitor)
However, I cannot manage to group per two values, say Debitor
and Creditor
. Ideally, I would like to group considering Debitor
AND Creditor
, while appling an aggregator function "Sum" for the Spend
property.
In other words, I'd like to achieve the F# equivalent of the following LINQ query:
var transactions_GroupSameDebitorCreditor =
transactions
.GroupBy(ts => new { ts.Debitor, ts.Creditor }) // group by multiple values
.Select(gr => new
{
Debitor = gr.Key.Debitor,
Debit = gr.Sum(trans => trans.Spend), //sum the trans values per grouped relationships
Creditor = gr.Key.Creditor
});
Where a IEnumerable of anonymous type was returned.
c# linq f# grouping
add a comment |
F#. I have a list transactions
of the following type:
type Transaction(Debitor: string, Spend:float, Creditor:string) =
member this.Debitor = Debitor
member this.Spend = Spend
member this.Creditor = Creditor
I know how to group by one value. Say for example I want to group per property Debitor
, it's easy to use that property as the Key of the group:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> ts.Debitor)
However, I cannot manage to group per two values, say Debitor
and Creditor
. Ideally, I would like to group considering Debitor
AND Creditor
, while appling an aggregator function "Sum" for the Spend
property.
In other words, I'd like to achieve the F# equivalent of the following LINQ query:
var transactions_GroupSameDebitorCreditor =
transactions
.GroupBy(ts => new { ts.Debitor, ts.Creditor }) // group by multiple values
.Select(gr => new
{
Debitor = gr.Key.Debitor,
Debit = gr.Sum(trans => trans.Spend), //sum the trans values per grouped relationships
Creditor = gr.Key.Creditor
});
Where a IEnumerable of anonymous type was returned.
c# linq f# grouping
add a comment |
F#. I have a list transactions
of the following type:
type Transaction(Debitor: string, Spend:float, Creditor:string) =
member this.Debitor = Debitor
member this.Spend = Spend
member this.Creditor = Creditor
I know how to group by one value. Say for example I want to group per property Debitor
, it's easy to use that property as the Key of the group:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> ts.Debitor)
However, I cannot manage to group per two values, say Debitor
and Creditor
. Ideally, I would like to group considering Debitor
AND Creditor
, while appling an aggregator function "Sum" for the Spend
property.
In other words, I'd like to achieve the F# equivalent of the following LINQ query:
var transactions_GroupSameDebitorCreditor =
transactions
.GroupBy(ts => new { ts.Debitor, ts.Creditor }) // group by multiple values
.Select(gr => new
{
Debitor = gr.Key.Debitor,
Debit = gr.Sum(trans => trans.Spend), //sum the trans values per grouped relationships
Creditor = gr.Key.Creditor
});
Where a IEnumerable of anonymous type was returned.
c# linq f# grouping
F#. I have a list transactions
of the following type:
type Transaction(Debitor: string, Spend:float, Creditor:string) =
member this.Debitor = Debitor
member this.Spend = Spend
member this.Creditor = Creditor
I know how to group by one value. Say for example I want to group per property Debitor
, it's easy to use that property as the Key of the group:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> ts.Debitor)
However, I cannot manage to group per two values, say Debitor
and Creditor
. Ideally, I would like to group considering Debitor
AND Creditor
, while appling an aggregator function "Sum" for the Spend
property.
In other words, I'd like to achieve the F# equivalent of the following LINQ query:
var transactions_GroupSameDebitorCreditor =
transactions
.GroupBy(ts => new { ts.Debitor, ts.Creditor }) // group by multiple values
.Select(gr => new
{
Debitor = gr.Key.Debitor,
Debit = gr.Sum(trans => trans.Spend), //sum the trans values per grouped relationships
Creditor = gr.Key.Creditor
});
Where a IEnumerable of anonymous type was returned.
c# linq f# grouping
c# linq f# grouping
edited Nov 24 '18 at 18:16
alexlomba87
asked Nov 24 '18 at 17:21
alexlomba87alexlomba87
182313
182313
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
You can use a tuple as the group key like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
If you want to aggregate the transactions of each group to sum the Spend property, you can do it like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
|> Seq.map(fun ((debitor, creditor), values) -> ( debitor, creditor, values |> Seq.sumBy (fun t -> t.Spend)))
Notice how I use pattern matching with the pattern ((debitor, creditor), values)
to be able to access the two parts of the group key and the sequence of transactions for each group (values
)
I see. So the last pipeline operator|> Seq.sumBy (fun t -> t.Spend)
is applied only tovalues
in order to sum only theSpend
property, and thesumBy
method is used to specify a function, which you couldn't with thesum
method. Very useful, thank you.
– alexlomba87
Nov 24 '18 at 18:09
1
sumBy
is a useful shortcut. You can dovalues |> Seq.map (fun t -> t.Spend) |> Seq.sum
instead if you want to.
– Yacoub Massad
Nov 24 '18 at 18:28
add a comment |
let sumTransactions (transactions: Transaction list) =
transactions
|> Seq.groupBy(fun ts -> (ts.Creditor, ts.Debitor))
|> Seq.map (fun ((cred, deb), ts) ->
let s = ts |> Seq.sumBy (fun t -> t.Spend)
Transaction(deb, s , cred))
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53460612%2ff-group-by-more-than-one-value-and-aggregate%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can use a tuple as the group key like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
If you want to aggregate the transactions of each group to sum the Spend property, you can do it like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
|> Seq.map(fun ((debitor, creditor), values) -> ( debitor, creditor, values |> Seq.sumBy (fun t -> t.Spend)))
Notice how I use pattern matching with the pattern ((debitor, creditor), values)
to be able to access the two parts of the group key and the sequence of transactions for each group (values
)
I see. So the last pipeline operator|> Seq.sumBy (fun t -> t.Spend)
is applied only tovalues
in order to sum only theSpend
property, and thesumBy
method is used to specify a function, which you couldn't with thesum
method. Very useful, thank you.
– alexlomba87
Nov 24 '18 at 18:09
1
sumBy
is a useful shortcut. You can dovalues |> Seq.map (fun t -> t.Spend) |> Seq.sum
instead if you want to.
– Yacoub Massad
Nov 24 '18 at 18:28
add a comment |
You can use a tuple as the group key like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
If you want to aggregate the transactions of each group to sum the Spend property, you can do it like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
|> Seq.map(fun ((debitor, creditor), values) -> ( debitor, creditor, values |> Seq.sumBy (fun t -> t.Spend)))
Notice how I use pattern matching with the pattern ((debitor, creditor), values)
to be able to access the two parts of the group key and the sequence of transactions for each group (values
)
I see. So the last pipeline operator|> Seq.sumBy (fun t -> t.Spend)
is applied only tovalues
in order to sum only theSpend
property, and thesumBy
method is used to specify a function, which you couldn't with thesum
method. Very useful, thank you.
– alexlomba87
Nov 24 '18 at 18:09
1
sumBy
is a useful shortcut. You can dovalues |> Seq.map (fun t -> t.Spend) |> Seq.sum
instead if you want to.
– Yacoub Massad
Nov 24 '18 at 18:28
add a comment |
You can use a tuple as the group key like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
If you want to aggregate the transactions of each group to sum the Spend property, you can do it like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
|> Seq.map(fun ((debitor, creditor), values) -> ( debitor, creditor, values |> Seq.sumBy (fun t -> t.Spend)))
Notice how I use pattern matching with the pattern ((debitor, creditor), values)
to be able to access the two parts of the group key and the sequence of transactions for each group (values
)
You can use a tuple as the group key like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
If you want to aggregate the transactions of each group to sum the Spend property, you can do it like this:
let tsGroupDebitor =
transactions
|> Seq.groupBy(fun ts -> (ts.Debitor, ts.Creditor))
|> Seq.map(fun ((debitor, creditor), values) -> ( debitor, creditor, values |> Seq.sumBy (fun t -> t.Spend)))
Notice how I use pattern matching with the pattern ((debitor, creditor), values)
to be able to access the two parts of the group key and the sequence of transactions for each group (values
)
edited Nov 24 '18 at 17:43
answered Nov 24 '18 at 17:30
Yacoub MassadYacoub Massad
23.7k21942
23.7k21942
I see. So the last pipeline operator|> Seq.sumBy (fun t -> t.Spend)
is applied only tovalues
in order to sum only theSpend
property, and thesumBy
method is used to specify a function, which you couldn't with thesum
method. Very useful, thank you.
– alexlomba87
Nov 24 '18 at 18:09
1
sumBy
is a useful shortcut. You can dovalues |> Seq.map (fun t -> t.Spend) |> Seq.sum
instead if you want to.
– Yacoub Massad
Nov 24 '18 at 18:28
add a comment |
I see. So the last pipeline operator|> Seq.sumBy (fun t -> t.Spend)
is applied only tovalues
in order to sum only theSpend
property, and thesumBy
method is used to specify a function, which you couldn't with thesum
method. Very useful, thank you.
– alexlomba87
Nov 24 '18 at 18:09
1
sumBy
is a useful shortcut. You can dovalues |> Seq.map (fun t -> t.Spend) |> Seq.sum
instead if you want to.
– Yacoub Massad
Nov 24 '18 at 18:28
I see. So the last pipeline operator
|> Seq.sumBy (fun t -> t.Spend)
is applied only to values
in order to sum only the Spend
property, and the sumBy
method is used to specify a function, which you couldn't with the sum
method. Very useful, thank you.– alexlomba87
Nov 24 '18 at 18:09
I see. So the last pipeline operator
|> Seq.sumBy (fun t -> t.Spend)
is applied only to values
in order to sum only the Spend
property, and the sumBy
method is used to specify a function, which you couldn't with the sum
method. Very useful, thank you.– alexlomba87
Nov 24 '18 at 18:09
1
1
sumBy
is a useful shortcut. You can do values |> Seq.map (fun t -> t.Spend) |> Seq.sum
instead if you want to.– Yacoub Massad
Nov 24 '18 at 18:28
sumBy
is a useful shortcut. You can do values |> Seq.map (fun t -> t.Spend) |> Seq.sum
instead if you want to.– Yacoub Massad
Nov 24 '18 at 18:28
add a comment |
let sumTransactions (transactions: Transaction list) =
transactions
|> Seq.groupBy(fun ts -> (ts.Creditor, ts.Debitor))
|> Seq.map (fun ((cred, deb), ts) ->
let s = ts |> Seq.sumBy (fun t -> t.Spend)
Transaction(deb, s , cred))
add a comment |
let sumTransactions (transactions: Transaction list) =
transactions
|> Seq.groupBy(fun ts -> (ts.Creditor, ts.Debitor))
|> Seq.map (fun ((cred, deb), ts) ->
let s = ts |> Seq.sumBy (fun t -> t.Spend)
Transaction(deb, s , cred))
add a comment |
let sumTransactions (transactions: Transaction list) =
transactions
|> Seq.groupBy(fun ts -> (ts.Creditor, ts.Debitor))
|> Seq.map (fun ((cred, deb), ts) ->
let s = ts |> Seq.sumBy (fun t -> t.Spend)
Transaction(deb, s , cred))
let sumTransactions (transactions: Transaction list) =
transactions
|> Seq.groupBy(fun ts -> (ts.Creditor, ts.Debitor))
|> Seq.map (fun ((cred, deb), ts) ->
let s = ts |> Seq.sumBy (fun t -> t.Spend)
Transaction(deb, s , cred))
answered Nov 24 '18 at 17:32
LeeLee
120k14175245
120k14175245
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53460612%2ff-group-by-more-than-one-value-and-aggregate%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown