Creating Python defaultdict using nested list of tuples










1















The scenario is that I have a 2-D list. Each item of the inner list is tuple (key, value pair). The key might repeat in the list. I want to create a default-dict on the fly, in such a way that finally, the dictionary stores the key, and the cumulative sum of all the values of that key from the 2-D list.



To put the code :



listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
finalDict = defaultdict(int)
for eachItem in listOfItems:
for key, val in eachItem:
finalDict[key] += val
print(finalDict)


This is giving me what I want : defaultdict(<class 'int'>, 'a': 7, 'b': 5, 'c': 0, 'd': 5) but I am looking for a more 'Pythonic' way using comprehensions. So I tried the below :



finalDict = defaultdict(int)
finalDict = key : finalDict[key]+val for eachItem in listOfItems for key, val in eachItem
print(finalDict)


But the output is : 'a': 6, 'b': 2, 'c': 0, 'd': 5 What is it that I am doing wrong? Or is it that when using comprehension the Dictionary is not created and modified on the fly?










share|improve this question


























    1















    The scenario is that I have a 2-D list. Each item of the inner list is tuple (key, value pair). The key might repeat in the list. I want to create a default-dict on the fly, in such a way that finally, the dictionary stores the key, and the cumulative sum of all the values of that key from the 2-D list.



    To put the code :



    listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
    finalDict = defaultdict(int)
    for eachItem in listOfItems:
    for key, val in eachItem:
    finalDict[key] += val
    print(finalDict)


    This is giving me what I want : defaultdict(<class 'int'>, 'a': 7, 'b': 5, 'c': 0, 'd': 5) but I am looking for a more 'Pythonic' way using comprehensions. So I tried the below :



    finalDict = defaultdict(int)
    finalDict = key : finalDict[key]+val for eachItem in listOfItems for key, val in eachItem
    print(finalDict)


    But the output is : 'a': 6, 'b': 2, 'c': 0, 'd': 5 What is it that I am doing wrong? Or is it that when using comprehension the Dictionary is not created and modified on the fly?










    share|improve this question
























      1












      1








      1








      The scenario is that I have a 2-D list. Each item of the inner list is tuple (key, value pair). The key might repeat in the list. I want to create a default-dict on the fly, in such a way that finally, the dictionary stores the key, and the cumulative sum of all the values of that key from the 2-D list.



      To put the code :



      listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
      finalDict = defaultdict(int)
      for eachItem in listOfItems:
      for key, val in eachItem:
      finalDict[key] += val
      print(finalDict)


      This is giving me what I want : defaultdict(<class 'int'>, 'a': 7, 'b': 5, 'c': 0, 'd': 5) but I am looking for a more 'Pythonic' way using comprehensions. So I tried the below :



      finalDict = defaultdict(int)
      finalDict = key : finalDict[key]+val for eachItem in listOfItems for key, val in eachItem
      print(finalDict)


      But the output is : 'a': 6, 'b': 2, 'c': 0, 'd': 5 What is it that I am doing wrong? Or is it that when using comprehension the Dictionary is not created and modified on the fly?










      share|improve this question














      The scenario is that I have a 2-D list. Each item of the inner list is tuple (key, value pair). The key might repeat in the list. I want to create a default-dict on the fly, in such a way that finally, the dictionary stores the key, and the cumulative sum of all the values of that key from the 2-D list.



      To put the code :



      listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
      finalDict = defaultdict(int)
      for eachItem in listOfItems:
      for key, val in eachItem:
      finalDict[key] += val
      print(finalDict)


      This is giving me what I want : defaultdict(<class 'int'>, 'a': 7, 'b': 5, 'c': 0, 'd': 5) but I am looking for a more 'Pythonic' way using comprehensions. So I tried the below :



      finalDict = defaultdict(int)
      finalDict = key : finalDict[key]+val for eachItem in listOfItems for key, val in eachItem
      print(finalDict)


      But the output is : 'a': 6, 'b': 2, 'c': 0, 'd': 5 What is it that I am doing wrong? Or is it that when using comprehension the Dictionary is not created and modified on the fly?







      python python-3.x nested-lists defaultdict dictionary-comprehension






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 13 '18 at 14:56









      PrincePrince

      738




      738






















          4 Answers
          4






          active

          oldest

          votes


















          5














          Yes a comprehension can't be updated on-the-fly. Anyway, this task might be better suited to collections.Counter() with .update() calls:



          >>> from collections import Counter
          >>> c = Counter()
          >>> for eachItem in listOfItems:
          ... c.update(dict(eachItem))
          ...
          >>> c
          Counter('a': 7, 'b': 5, 'd': 5, 'c': 0)





          share|improve this answer

























          • Ok.. I should have mentioned, the values in the list can be float too. I missed that point trying to simplify my question. Any way to handle that @Chris_Rands? Thanks for help..!

            – Prince
            Nov 13 '18 at 17:48


















          2














          This is because you do not assign any value to your finalDict inside your dict in comprehension.



          In your dict in comprehension you are literally changing the type of finalDict



          As far as I know you cannot assign value to your dict inside a dict in comprehension.



          Here is a way to get the dictionnary you want



          from functools import reduce

          listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

          list_dict = [key: val for eachItem in listOfItems for key, val in eachItem]

          def sum_dict(x, y):
          return k: x.get(k, 0) + y.get(k, 0) for k in set(x)
          print(reduce(sum_dict, list_dict))





          share|improve this answer






























            2














            Simple solution without using additional modules:



            inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

            l = [item for sublist in inp_list for item in sublist] # flatten the list

            sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]

            print(sums)





            share|improve this answer




















            • 1





              notice you can use itertools.chain(*inp_list) to flatten the list

              – Aaron_ab
              Dec 9 '18 at 13:07



















            1














            trying to use python's built-in methods instead of coding the functionality myself:



            The long and explained solution



            from itertools import chain, groupby
            from operator import itemgetter

            listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

            # just flat the list of lists into 1 list..
            flatten_list = chain(*listOfItems)

            # get all elements grouped by the key, e.g 'a', 'b' etc..
            first = itemgetter(0)
            groupedByKey = groupby(sorted(flatten_list, key=first), key=first))

            #sum
            summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)

            # create a dict
            d = dict(summed_by_key)

            print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5


            ~one line solution



            from itertools import chain, groupby
            from operator import itemgetter

            first = itemgetter(0)
            d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))

            print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5





            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%2f53283759%2fcreating-python-defaultdict-using-nested-list-of-tuples%23new-answer', 'question_page');

              );

              Post as a guest















              Required, but never shown

























              4 Answers
              4






              active

              oldest

              votes








              4 Answers
              4






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              5














              Yes a comprehension can't be updated on-the-fly. Anyway, this task might be better suited to collections.Counter() with .update() calls:



              >>> from collections import Counter
              >>> c = Counter()
              >>> for eachItem in listOfItems:
              ... c.update(dict(eachItem))
              ...
              >>> c
              Counter('a': 7, 'b': 5, 'd': 5, 'c': 0)





              share|improve this answer

























              • Ok.. I should have mentioned, the values in the list can be float too. I missed that point trying to simplify my question. Any way to handle that @Chris_Rands? Thanks for help..!

                – Prince
                Nov 13 '18 at 17:48















              5














              Yes a comprehension can't be updated on-the-fly. Anyway, this task might be better suited to collections.Counter() with .update() calls:



              >>> from collections import Counter
              >>> c = Counter()
              >>> for eachItem in listOfItems:
              ... c.update(dict(eachItem))
              ...
              >>> c
              Counter('a': 7, 'b': 5, 'd': 5, 'c': 0)





              share|improve this answer

























              • Ok.. I should have mentioned, the values in the list can be float too. I missed that point trying to simplify my question. Any way to handle that @Chris_Rands? Thanks for help..!

                – Prince
                Nov 13 '18 at 17:48













              5












              5








              5







              Yes a comprehension can't be updated on-the-fly. Anyway, this task might be better suited to collections.Counter() with .update() calls:



              >>> from collections import Counter
              >>> c = Counter()
              >>> for eachItem in listOfItems:
              ... c.update(dict(eachItem))
              ...
              >>> c
              Counter('a': 7, 'b': 5, 'd': 5, 'c': 0)





              share|improve this answer















              Yes a comprehension can't be updated on-the-fly. Anyway, this task might be better suited to collections.Counter() with .update() calls:



              >>> from collections import Counter
              >>> c = Counter()
              >>> for eachItem in listOfItems:
              ... c.update(dict(eachItem))
              ...
              >>> c
              Counter('a': 7, 'b': 5, 'd': 5, 'c': 0)






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 13 '18 at 15:20

























              answered Nov 13 '18 at 15:02









              Chris_RandsChris_Rands

              16.1k53870




              16.1k53870












              • Ok.. I should have mentioned, the values in the list can be float too. I missed that point trying to simplify my question. Any way to handle that @Chris_Rands? Thanks for help..!

                – Prince
                Nov 13 '18 at 17:48

















              • Ok.. I should have mentioned, the values in the list can be float too. I missed that point trying to simplify my question. Any way to handle that @Chris_Rands? Thanks for help..!

                – Prince
                Nov 13 '18 at 17:48
















              Ok.. I should have mentioned, the values in the list can be float too. I missed that point trying to simplify my question. Any way to handle that @Chris_Rands? Thanks for help..!

              – Prince
              Nov 13 '18 at 17:48





              Ok.. I should have mentioned, the values in the list can be float too. I missed that point trying to simplify my question. Any way to handle that @Chris_Rands? Thanks for help..!

              – Prince
              Nov 13 '18 at 17:48













              2














              This is because you do not assign any value to your finalDict inside your dict in comprehension.



              In your dict in comprehension you are literally changing the type of finalDict



              As far as I know you cannot assign value to your dict inside a dict in comprehension.



              Here is a way to get the dictionnary you want



              from functools import reduce

              listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

              list_dict = [key: val for eachItem in listOfItems for key, val in eachItem]

              def sum_dict(x, y):
              return k: x.get(k, 0) + y.get(k, 0) for k in set(x)
              print(reduce(sum_dict, list_dict))





              share|improve this answer



























                2














                This is because you do not assign any value to your finalDict inside your dict in comprehension.



                In your dict in comprehension you are literally changing the type of finalDict



                As far as I know you cannot assign value to your dict inside a dict in comprehension.



                Here is a way to get the dictionnary you want



                from functools import reduce

                listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                list_dict = [key: val for eachItem in listOfItems for key, val in eachItem]

                def sum_dict(x, y):
                return k: x.get(k, 0) + y.get(k, 0) for k in set(x)
                print(reduce(sum_dict, list_dict))





                share|improve this answer

























                  2












                  2








                  2







                  This is because you do not assign any value to your finalDict inside your dict in comprehension.



                  In your dict in comprehension you are literally changing the type of finalDict



                  As far as I know you cannot assign value to your dict inside a dict in comprehension.



                  Here is a way to get the dictionnary you want



                  from functools import reduce

                  listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                  list_dict = [key: val for eachItem in listOfItems for key, val in eachItem]

                  def sum_dict(x, y):
                  return k: x.get(k, 0) + y.get(k, 0) for k in set(x)
                  print(reduce(sum_dict, list_dict))





                  share|improve this answer













                  This is because you do not assign any value to your finalDict inside your dict in comprehension.



                  In your dict in comprehension you are literally changing the type of finalDict



                  As far as I know you cannot assign value to your dict inside a dict in comprehension.



                  Here is a way to get the dictionnary you want



                  from functools import reduce

                  listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                  list_dict = [key: val for eachItem in listOfItems for key, val in eachItem]

                  def sum_dict(x, y):
                  return k: x.get(k, 0) + y.get(k, 0) for k in set(x)
                  print(reduce(sum_dict, list_dict))






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 13 '18 at 15:24









                  BlueSheepTokenBlueSheepToken

                  1,348516




                  1,348516





















                      2














                      Simple solution without using additional modules:



                      inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                      l = [item for sublist in inp_list for item in sublist] # flatten the list

                      sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]

                      print(sums)





                      share|improve this answer




















                      • 1





                        notice you can use itertools.chain(*inp_list) to flatten the list

                        – Aaron_ab
                        Dec 9 '18 at 13:07
















                      2














                      Simple solution without using additional modules:



                      inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                      l = [item for sublist in inp_list for item in sublist] # flatten the list

                      sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]

                      print(sums)





                      share|improve this answer




















                      • 1





                        notice you can use itertools.chain(*inp_list) to flatten the list

                        – Aaron_ab
                        Dec 9 '18 at 13:07














                      2












                      2








                      2







                      Simple solution without using additional modules:



                      inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                      l = [item for sublist in inp_list for item in sublist] # flatten the list

                      sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]

                      print(sums)





                      share|improve this answer















                      Simple solution without using additional modules:



                      inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                      l = [item for sublist in inp_list for item in sublist] # flatten the list

                      sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]

                      print(sums)






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Nov 13 '18 at 21:56

























                      answered Nov 13 '18 at 15:18









                      svfatsvfat

                      1,055626




                      1,055626







                      • 1





                        notice you can use itertools.chain(*inp_list) to flatten the list

                        – Aaron_ab
                        Dec 9 '18 at 13:07













                      • 1





                        notice you can use itertools.chain(*inp_list) to flatten the list

                        – Aaron_ab
                        Dec 9 '18 at 13:07








                      1




                      1





                      notice you can use itertools.chain(*inp_list) to flatten the list

                      – Aaron_ab
                      Dec 9 '18 at 13:07






                      notice you can use itertools.chain(*inp_list) to flatten the list

                      – Aaron_ab
                      Dec 9 '18 at 13:07












                      1














                      trying to use python's built-in methods instead of coding the functionality myself:



                      The long and explained solution



                      from itertools import chain, groupby
                      from operator import itemgetter

                      listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                      # just flat the list of lists into 1 list..
                      flatten_list = chain(*listOfItems)

                      # get all elements grouped by the key, e.g 'a', 'b' etc..
                      first = itemgetter(0)
                      groupedByKey = groupby(sorted(flatten_list, key=first), key=first))

                      #sum
                      summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)

                      # create a dict
                      d = dict(summed_by_key)

                      print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5


                      ~one line solution



                      from itertools import chain, groupby
                      from operator import itemgetter

                      first = itemgetter(0)
                      d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))

                      print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5





                      share|improve this answer



























                        1














                        trying to use python's built-in methods instead of coding the functionality myself:



                        The long and explained solution



                        from itertools import chain, groupby
                        from operator import itemgetter

                        listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                        # just flat the list of lists into 1 list..
                        flatten_list = chain(*listOfItems)

                        # get all elements grouped by the key, e.g 'a', 'b' etc..
                        first = itemgetter(0)
                        groupedByKey = groupby(sorted(flatten_list, key=first), key=first))

                        #sum
                        summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)

                        # create a dict
                        d = dict(summed_by_key)

                        print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5


                        ~one line solution



                        from itertools import chain, groupby
                        from operator import itemgetter

                        first = itemgetter(0)
                        d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))

                        print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5





                        share|improve this answer

























                          1












                          1








                          1







                          trying to use python's built-in methods instead of coding the functionality myself:



                          The long and explained solution



                          from itertools import chain, groupby
                          from operator import itemgetter

                          listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                          # just flat the list of lists into 1 list..
                          flatten_list = chain(*listOfItems)

                          # get all elements grouped by the key, e.g 'a', 'b' etc..
                          first = itemgetter(0)
                          groupedByKey = groupby(sorted(flatten_list, key=first), key=first))

                          #sum
                          summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)

                          # create a dict
                          d = dict(summed_by_key)

                          print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5


                          ~one line solution



                          from itertools import chain, groupby
                          from operator import itemgetter

                          first = itemgetter(0)
                          d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))

                          print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5





                          share|improve this answer













                          trying to use python's built-in methods instead of coding the functionality myself:



                          The long and explained solution



                          from itertools import chain, groupby
                          from operator import itemgetter

                          listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]

                          # just flat the list of lists into 1 list..
                          flatten_list = chain(*listOfItems)

                          # get all elements grouped by the key, e.g 'a', 'b' etc..
                          first = itemgetter(0)
                          groupedByKey = groupby(sorted(flatten_list, key=first), key=first))

                          #sum
                          summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)

                          # create a dict
                          d = dict(summed_by_key)

                          print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5


                          ~one line solution



                          from itertools import chain, groupby
                          from operator import itemgetter

                          first = itemgetter(0)
                          d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))

                          print(d) # 'a': 7, 'b': 5, 'c': 0, 'd': 5






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Dec 9 '18 at 13:07









                          Aaron_abAaron_ab

                          1,013723




                          1,013723



























                              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%2f53283759%2fcreating-python-defaultdict-using-nested-list-of-tuples%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







                              這個網誌中的熱門文章

                              Barbados

                              How to read a connectionString WITH PROVIDER in .NET Core?

                              Node.js Script on GitHub Pages or Amazon S3