F# group by more than one value and aggregate












1















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.










share|improve this question





























    1















    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.










    share|improve this question



























      1












      1








      1


      1






      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.










      share|improve this question
















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 24 '18 at 18:16







      alexlomba87

















      asked Nov 24 '18 at 17:21









      alexlomba87alexlomba87

      182313




      182313
























          2 Answers
          2






          active

          oldest

          votes


















          3














          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)






          share|improve this answer


























          • 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





            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





















          1














          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))





          share|improve this answer























            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
            });


            }
            });














            draft saved

            draft discarded


















            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









            3














            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)






            share|improve this answer


























            • 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





              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


















            3














            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)






            share|improve this answer


























            • 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





              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
















            3












            3








            3







            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)






            share|improve this answer















            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)







            share|improve this answer














            share|improve this answer



            share|improve this answer








            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 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





              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





















            • 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





              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



















            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















            1














            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))





            share|improve this answer




























              1














              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))





              share|improve this answer


























                1












                1








                1







                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))





                share|improve this answer













                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))






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 24 '18 at 17:32









                LeeLee

                120k14175245




                120k14175245






























                    draft saved

                    draft discarded




















































                    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.




                    draft saved


                    draft discarded














                    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





















































                    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







                    Popular posts from this blog

                    Wiesbaden

                    Marschland

                    Dieringhausen