Merge list of maps into a single map by summing values





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







12















I have a class Values:



public class Values {
private int count;
private int values;
}


And a list of multiple maps of type Map<String, Values>



Map<String, Values> map1 = new HashMap<>();
map1 .put("aaa", new Values(1, 10));
map1 .put("bbb", new Values(5, 50));
map1 .put("ccc", new Values(2, 30));

Map<String, Values> map2= new HashMap<>();
map2.put("aaa", new Values(2, 20));
map2.put("bbb", new Values(3, 50));
map2.put("ccc", new Values(3, 10));

List<Map<String, Values>> list = Arrays.asList(map1, map2);


There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.



I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:



{
aaa= {
count = 3,
value = 30
},
bbb= {
count = 8,
value = 100
},
ccc= {
count = 6,
value = 40
}
}


I am trying to achieve this using the Streams API, but I am stuck:



public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream()) ...?
}


How can I group each entry by their keys and add up each count and each value into a single map?



Thank you in advance.










share|improve this question































    12















    I have a class Values:



    public class Values {
    private int count;
    private int values;
    }


    And a list of multiple maps of type Map<String, Values>



    Map<String, Values> map1 = new HashMap<>();
    map1 .put("aaa", new Values(1, 10));
    map1 .put("bbb", new Values(5, 50));
    map1 .put("ccc", new Values(2, 30));

    Map<String, Values> map2= new HashMap<>();
    map2.put("aaa", new Values(2, 20));
    map2.put("bbb", new Values(3, 50));
    map2.put("ccc", new Values(3, 10));

    List<Map<String, Values>> list = Arrays.asList(map1, map2);


    There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.



    I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:



    {
    aaa= {
    count = 3,
    value = 30
    },
    bbb= {
    count = 8,
    value = 100
    },
    ccc= {
    count = 6,
    value = 40
    }
    }


    I am trying to achieve this using the Streams API, but I am stuck:



    public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
    return maps.stream()
    .flatMap(m -> m.entrySet().stream()) ...?
    }


    How can I group each entry by their keys and add up each count and each value into a single map?



    Thank you in advance.










    share|improve this question



























      12












      12








      12


      3






      I have a class Values:



      public class Values {
      private int count;
      private int values;
      }


      And a list of multiple maps of type Map<String, Values>



      Map<String, Values> map1 = new HashMap<>();
      map1 .put("aaa", new Values(1, 10));
      map1 .put("bbb", new Values(5, 50));
      map1 .put("ccc", new Values(2, 30));

      Map<String, Values> map2= new HashMap<>();
      map2.put("aaa", new Values(2, 20));
      map2.put("bbb", new Values(3, 50));
      map2.put("ccc", new Values(3, 10));

      List<Map<String, Values>> list = Arrays.asList(map1, map2);


      There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.



      I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:



      {
      aaa= {
      count = 3,
      value = 30
      },
      bbb= {
      count = 8,
      value = 100
      },
      ccc= {
      count = 6,
      value = 40
      }
      }


      I am trying to achieve this using the Streams API, but I am stuck:



      public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
      return maps.stream()
      .flatMap(m -> m.entrySet().stream()) ...?
      }


      How can I group each entry by their keys and add up each count and each value into a single map?



      Thank you in advance.










      share|improve this question
















      I have a class Values:



      public class Values {
      private int count;
      private int values;
      }


      And a list of multiple maps of type Map<String, Values>



      Map<String, Values> map1 = new HashMap<>();
      map1 .put("aaa", new Values(1, 10));
      map1 .put("bbb", new Values(5, 50));
      map1 .put("ccc", new Values(2, 30));

      Map<String, Values> map2= new HashMap<>();
      map2.put("aaa", new Values(2, 20));
      map2.put("bbb", new Values(3, 50));
      map2.put("ccc", new Values(3, 10));

      List<Map<String, Values>> list = Arrays.asList(map1, map2);


      There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.



      I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:



      {
      aaa= {
      count = 3,
      value = 30
      },
      bbb= {
      count = 8,
      value = 100
      },
      ccc= {
      count = 6,
      value = 40
      }
      }


      I am trying to achieve this using the Streams API, but I am stuck:



      public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
      return maps.stream()
      .flatMap(m -> m.entrySet().stream()) ...?
      }


      How can I group each entry by their keys and add up each count and each value into a single map?



      Thank you in advance.







      java java-8 java-stream






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Feb 10 at 10:31









      Ruslan

      4,57611230




      4,57611230










      asked Feb 10 at 9:32









      stk020305stk020305

      636




      636
























          2 Answers
          2






          active

          oldest

          votes


















          11














          You can collect the entries of your Stream with a toMap collector, with a merge function.



          public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
          return maps.stream()
          .flatMap(m -> m.entrySet().stream())
          .collect(Collectors.toMap(Map.Entry::getKey,
          Map.Entry::getValue,
          (v1,v2) -> new Values(v1,v2)));
          }


          Assuming you have a Values constructor that takes two Values instances and creates an instance having the sums of the values.



          Of course, you can write the merge function without that constructor. For example:



          (v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())





          share|improve this answer





















          • 2





            Regarding the constructor that two Values to represent (v1,v2) -> new Values(v1,v2), I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new would rather be clean. Though using a static method to add these attributes and return back a Value shall be a better choice in my opinion.

            – Naman
            Feb 10 at 12:05





















          7














          One more solution with groupingBy:



          Map<String, Optional<Values>> collect = list.stream()
          .flatMap(map -> map.entrySet().stream())
          .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
          reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));


          Note: values of this map are Optional<Values>.
          If you have null value on one of your source map like map2.put("ddd", null);
          it allows to avoid NullPointerException and return Optional.empty






          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%2f54615078%2fmerge-list-of-maps-into-a-single-map-by-summing-values%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









            11














            You can collect the entries of your Stream with a toMap collector, with a merge function.



            public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
            return maps.stream()
            .flatMap(m -> m.entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey,
            Map.Entry::getValue,
            (v1,v2) -> new Values(v1,v2)));
            }


            Assuming you have a Values constructor that takes two Values instances and creates an instance having the sums of the values.



            Of course, you can write the merge function without that constructor. For example:



            (v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())





            share|improve this answer





















            • 2





              Regarding the constructor that two Values to represent (v1,v2) -> new Values(v1,v2), I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new would rather be clean. Though using a static method to add these attributes and return back a Value shall be a better choice in my opinion.

              – Naman
              Feb 10 at 12:05


















            11














            You can collect the entries of your Stream with a toMap collector, with a merge function.



            public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
            return maps.stream()
            .flatMap(m -> m.entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey,
            Map.Entry::getValue,
            (v1,v2) -> new Values(v1,v2)));
            }


            Assuming you have a Values constructor that takes two Values instances and creates an instance having the sums of the values.



            Of course, you can write the merge function without that constructor. For example:



            (v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())





            share|improve this answer





















            • 2





              Regarding the constructor that two Values to represent (v1,v2) -> new Values(v1,v2), I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new would rather be clean. Though using a static method to add these attributes and return back a Value shall be a better choice in my opinion.

              – Naman
              Feb 10 at 12:05
















            11












            11








            11







            You can collect the entries of your Stream with a toMap collector, with a merge function.



            public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
            return maps.stream()
            .flatMap(m -> m.entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey,
            Map.Entry::getValue,
            (v1,v2) -> new Values(v1,v2)));
            }


            Assuming you have a Values constructor that takes two Values instances and creates an instance having the sums of the values.



            Of course, you can write the merge function without that constructor. For example:



            (v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())





            share|improve this answer















            You can collect the entries of your Stream with a toMap collector, with a merge function.



            public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
            return maps.stream()
            .flatMap(m -> m.entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey,
            Map.Entry::getValue,
            (v1,v2) -> new Values(v1,v2)));
            }


            Assuming you have a Values constructor that takes two Values instances and creates an instance having the sums of the values.



            Of course, you can write the merge function without that constructor. For example:



            (v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 10 at 9:43

























            answered Feb 10 at 9:37









            EranEran

            292k37481564




            292k37481564








            • 2





              Regarding the constructor that two Values to represent (v1,v2) -> new Values(v1,v2), I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new would rather be clean. Though using a static method to add these attributes and return back a Value shall be a better choice in my opinion.

              – Naman
              Feb 10 at 12:05
















            • 2





              Regarding the constructor that two Values to represent (v1,v2) -> new Values(v1,v2), I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new would rather be clean. Though using a static method to add these attributes and return back a Value shall be a better choice in my opinion.

              – Naman
              Feb 10 at 12:05










            2




            2





            Regarding the constructor that two Values to represent (v1,v2) -> new Values(v1,v2), I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new would rather be clean. Though using a static method to add these attributes and return back a Value shall be a better choice in my opinion.

            – Naman
            Feb 10 at 12:05







            Regarding the constructor that two Values to represent (v1,v2) -> new Values(v1,v2), I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new would rather be clean. Though using a static method to add these attributes and return back a Value shall be a better choice in my opinion.

            – Naman
            Feb 10 at 12:05















            7














            One more solution with groupingBy:



            Map<String, Optional<Values>> collect = list.stream()
            .flatMap(map -> map.entrySet().stream())
            .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
            reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));


            Note: values of this map are Optional<Values>.
            If you have null value on one of your source map like map2.put("ddd", null);
            it allows to avoid NullPointerException and return Optional.empty






            share|improve this answer




























              7














              One more solution with groupingBy:



              Map<String, Optional<Values>> collect = list.stream()
              .flatMap(map -> map.entrySet().stream())
              .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
              reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));


              Note: values of this map are Optional<Values>.
              If you have null value on one of your source map like map2.put("ddd", null);
              it allows to avoid NullPointerException and return Optional.empty






              share|improve this answer


























                7












                7








                7







                One more solution with groupingBy:



                Map<String, Optional<Values>> collect = list.stream()
                .flatMap(map -> map.entrySet().stream())
                .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
                reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));


                Note: values of this map are Optional<Values>.
                If you have null value on one of your source map like map2.put("ddd", null);
                it allows to avoid NullPointerException and return Optional.empty






                share|improve this answer













                One more solution with groupingBy:



                Map<String, Optional<Values>> collect = list.stream()
                .flatMap(map -> map.entrySet().stream())
                .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
                reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));


                Note: values of this map are Optional<Values>.
                If you have null value on one of your source map like map2.put("ddd", null);
                it allows to avoid NullPointerException and return Optional.empty







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Feb 10 at 10:11









                RuslanRuslan

                4,57611230




                4,57611230






























                    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%2f54615078%2fmerge-list-of-maps-into-a-single-map-by-summing-values%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

                    Human spaceflight

                    Can not write log (Is /dev/pts mounted?) - openpty in Ubuntu-on-Windows?

                    張江高科駅