csv dictionary does not reset to the beginning when looping through it multiple times












1















I am looping a CSV file, which is opened as dictionary. The problem is that while I loop through the rows in the dictionary, the main for loop goes to the next item. The dictionary does not reset to the first item when running the for loop. So if it gets to the last row, it doesn't change.



names = ['a', 'b', 'c', 'd', 'e', 'f']
source1_csv = open("output.csv", mode='r')
dictionary_csv = csv.DictReader(source1_csv)

for letters in names:
for entry in dictionary_csv:
print(entry["name"])
if entry['name'] == letters:
print("found it")


You can use any CSV file, just replace the key in the entry, and notice that if there is no match on the outer for loop, once that the next item in the names is selected, the inner for loop for the dictionary will just exit because the dictionary is already on the last position and does not reset.



How do I avoid this, so the position of the dictionary is reset and parse through every row for every entry of the names list?










share|improve this question





























    1















    I am looping a CSV file, which is opened as dictionary. The problem is that while I loop through the rows in the dictionary, the main for loop goes to the next item. The dictionary does not reset to the first item when running the for loop. So if it gets to the last row, it doesn't change.



    names = ['a', 'b', 'c', 'd', 'e', 'f']
    source1_csv = open("output.csv", mode='r')
    dictionary_csv = csv.DictReader(source1_csv)

    for letters in names:
    for entry in dictionary_csv:
    print(entry["name"])
    if entry['name'] == letters:
    print("found it")


    You can use any CSV file, just replace the key in the entry, and notice that if there is no match on the outer for loop, once that the next item in the names is selected, the inner for loop for the dictionary will just exit because the dictionary is already on the last position and does not reset.



    How do I avoid this, so the position of the dictionary is reset and parse through every row for every entry of the names list?










    share|improve this question



























      1












      1








      1








      I am looping a CSV file, which is opened as dictionary. The problem is that while I loop through the rows in the dictionary, the main for loop goes to the next item. The dictionary does not reset to the first item when running the for loop. So if it gets to the last row, it doesn't change.



      names = ['a', 'b', 'c', 'd', 'e', 'f']
      source1_csv = open("output.csv", mode='r')
      dictionary_csv = csv.DictReader(source1_csv)

      for letters in names:
      for entry in dictionary_csv:
      print(entry["name"])
      if entry['name'] == letters:
      print("found it")


      You can use any CSV file, just replace the key in the entry, and notice that if there is no match on the outer for loop, once that the next item in the names is selected, the inner for loop for the dictionary will just exit because the dictionary is already on the last position and does not reset.



      How do I avoid this, so the position of the dictionary is reset and parse through every row for every entry of the names list?










      share|improve this question
















      I am looping a CSV file, which is opened as dictionary. The problem is that while I loop through the rows in the dictionary, the main for loop goes to the next item. The dictionary does not reset to the first item when running the for loop. So if it gets to the last row, it doesn't change.



      names = ['a', 'b', 'c', 'd', 'e', 'f']
      source1_csv = open("output.csv", mode='r')
      dictionary_csv = csv.DictReader(source1_csv)

      for letters in names:
      for entry in dictionary_csv:
      print(entry["name"])
      if entry['name'] == letters:
      print("found it")


      You can use any CSV file, just replace the key in the entry, and notice that if there is no match on the outer for loop, once that the next item in the names is selected, the inner for loop for the dictionary will just exit because the dictionary is already on the last position and does not reset.



      How do I avoid this, so the position of the dictionary is reset and parse through every row for every entry of the names list?







      python csv






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 15 '18 at 8:36









      Steffi Keran Rani J

      9402829




      9402829










      asked Nov 15 '18 at 6:22









      heyjudeheyjude

      1628




      1628
























          2 Answers
          2






          active

          oldest

          votes


















          1














          Solution 1:



          From your code above, it doesn't look like that you need to iterate over the entire csv multiple times, you can just switch the loops like:



          for entry in dictionary_csv:
          for letters in names:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Switching the loop over dictionary_csv to outer loop will avoid looping over csv multiple times.



          Solution 2:



          But if you don't want to change the order of loops, you can simply convert the DictReader to list before consuming it yourself. This way, list will consume the reader, and return you a list of it, and you can iterate over it multiple times:



          dictionary_csv = list(csv.DictReader(source1_csv))


          But if your csv is rather big, creating a list out of it isn't recommended, as list size will be big.



          Solution 3:



          Instead of creating a list, you can also seek the source file source1_csv to 0 before the inner loop:



          for letters in names:
          source1_csv.seek(0)
          for entry in dictionary_csv:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          It will take the source file to the start, and dictionary_csv will read it again for you.



          Edit:



          As @merlyn pointed out in below comments, that the solution 3 will not work entirely correctly, because after seeking to 0, dictionary_csv will interpret the first line of the csv (headers) as a separate data row. So, you'll have to ignore a line after seeking to 0.



          source1_csv.seek(0)
          source1_csv.readline()


          Or, re-instantiate dictionary_csv everytime you seek source1_csv (For that, you can see @merlyn's answer below).






          share|improve this answer


























          • Thanks! It works once I cast it as list. Is there a way to iterate or reset the "index pointer" of the dictionary? Just curious to know if there is a way to do so.

            – heyjude
            Nov 15 '18 at 6:42






          • 1





            Yes, there is a way, you'll actually have to seek source1_csv to 0, and DictReader will read it again for you.

            – Muhammad Ahmad
            Nov 15 '18 at 6:47








          • 1





            @MuhammadAhmad There's a small bug in solution 3. If dictionary_csv is not re-instantiated every time you seek the start of the file, it will interpret the headers of the csv file as regular entries.

            – merlyn
            Nov 15 '18 at 7:09











          • Yes, thanks for pointing it out. I didn't notice it before. Let me just correct it.

            – Muhammad Ahmad
            Nov 15 '18 at 7:14











          • @merlyn Corrected. Thanks. You were right about dictionary_csv taking the row of headers as a separate data row, but instead of re-instantiating it, another variant could be to ignore the first line.

            – Muhammad Ahmad
            Nov 15 '18 at 7:17





















          2














          csv doesn't provide a way to reset the iterator but the file object interface does. You can reset a file to it's starting position using file.seek(0).



          names = ['a', 'b', 'c', 'd', 'e', 'f']
          source1_csv = open("output.csv", mode='r')

          for letters in names:
          source1_csv.seek(0)
          for entry in csv.DictReader(source1_csv):
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Of course, you can also store the entries in a list and iterate on the as many time as you want. But that won't with files too large to store in memory.






          share|improve this answer
























          • Excellent, thanks for the answer and clarification!

            – heyjude
            Nov 15 '18 at 18:49











          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%2f53313567%2fcsv-dictionary-does-not-reset-to-the-beginning-when-looping-through-it-multiple%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









          1














          Solution 1:



          From your code above, it doesn't look like that you need to iterate over the entire csv multiple times, you can just switch the loops like:



          for entry in dictionary_csv:
          for letters in names:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Switching the loop over dictionary_csv to outer loop will avoid looping over csv multiple times.



          Solution 2:



          But if you don't want to change the order of loops, you can simply convert the DictReader to list before consuming it yourself. This way, list will consume the reader, and return you a list of it, and you can iterate over it multiple times:



          dictionary_csv = list(csv.DictReader(source1_csv))


          But if your csv is rather big, creating a list out of it isn't recommended, as list size will be big.



          Solution 3:



          Instead of creating a list, you can also seek the source file source1_csv to 0 before the inner loop:



          for letters in names:
          source1_csv.seek(0)
          for entry in dictionary_csv:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          It will take the source file to the start, and dictionary_csv will read it again for you.



          Edit:



          As @merlyn pointed out in below comments, that the solution 3 will not work entirely correctly, because after seeking to 0, dictionary_csv will interpret the first line of the csv (headers) as a separate data row. So, you'll have to ignore a line after seeking to 0.



          source1_csv.seek(0)
          source1_csv.readline()


          Or, re-instantiate dictionary_csv everytime you seek source1_csv (For that, you can see @merlyn's answer below).






          share|improve this answer


























          • Thanks! It works once I cast it as list. Is there a way to iterate or reset the "index pointer" of the dictionary? Just curious to know if there is a way to do so.

            – heyjude
            Nov 15 '18 at 6:42






          • 1





            Yes, there is a way, you'll actually have to seek source1_csv to 0, and DictReader will read it again for you.

            – Muhammad Ahmad
            Nov 15 '18 at 6:47








          • 1





            @MuhammadAhmad There's a small bug in solution 3. If dictionary_csv is not re-instantiated every time you seek the start of the file, it will interpret the headers of the csv file as regular entries.

            – merlyn
            Nov 15 '18 at 7:09











          • Yes, thanks for pointing it out. I didn't notice it before. Let me just correct it.

            – Muhammad Ahmad
            Nov 15 '18 at 7:14











          • @merlyn Corrected. Thanks. You were right about dictionary_csv taking the row of headers as a separate data row, but instead of re-instantiating it, another variant could be to ignore the first line.

            – Muhammad Ahmad
            Nov 15 '18 at 7:17


















          1














          Solution 1:



          From your code above, it doesn't look like that you need to iterate over the entire csv multiple times, you can just switch the loops like:



          for entry in dictionary_csv:
          for letters in names:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Switching the loop over dictionary_csv to outer loop will avoid looping over csv multiple times.



          Solution 2:



          But if you don't want to change the order of loops, you can simply convert the DictReader to list before consuming it yourself. This way, list will consume the reader, and return you a list of it, and you can iterate over it multiple times:



          dictionary_csv = list(csv.DictReader(source1_csv))


          But if your csv is rather big, creating a list out of it isn't recommended, as list size will be big.



          Solution 3:



          Instead of creating a list, you can also seek the source file source1_csv to 0 before the inner loop:



          for letters in names:
          source1_csv.seek(0)
          for entry in dictionary_csv:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          It will take the source file to the start, and dictionary_csv will read it again for you.



          Edit:



          As @merlyn pointed out in below comments, that the solution 3 will not work entirely correctly, because after seeking to 0, dictionary_csv will interpret the first line of the csv (headers) as a separate data row. So, you'll have to ignore a line after seeking to 0.



          source1_csv.seek(0)
          source1_csv.readline()


          Or, re-instantiate dictionary_csv everytime you seek source1_csv (For that, you can see @merlyn's answer below).






          share|improve this answer


























          • Thanks! It works once I cast it as list. Is there a way to iterate or reset the "index pointer" of the dictionary? Just curious to know if there is a way to do so.

            – heyjude
            Nov 15 '18 at 6:42






          • 1





            Yes, there is a way, you'll actually have to seek source1_csv to 0, and DictReader will read it again for you.

            – Muhammad Ahmad
            Nov 15 '18 at 6:47








          • 1





            @MuhammadAhmad There's a small bug in solution 3. If dictionary_csv is not re-instantiated every time you seek the start of the file, it will interpret the headers of the csv file as regular entries.

            – merlyn
            Nov 15 '18 at 7:09











          • Yes, thanks for pointing it out. I didn't notice it before. Let me just correct it.

            – Muhammad Ahmad
            Nov 15 '18 at 7:14











          • @merlyn Corrected. Thanks. You were right about dictionary_csv taking the row of headers as a separate data row, but instead of re-instantiating it, another variant could be to ignore the first line.

            – Muhammad Ahmad
            Nov 15 '18 at 7:17
















          1












          1








          1







          Solution 1:



          From your code above, it doesn't look like that you need to iterate over the entire csv multiple times, you can just switch the loops like:



          for entry in dictionary_csv:
          for letters in names:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Switching the loop over dictionary_csv to outer loop will avoid looping over csv multiple times.



          Solution 2:



          But if you don't want to change the order of loops, you can simply convert the DictReader to list before consuming it yourself. This way, list will consume the reader, and return you a list of it, and you can iterate over it multiple times:



          dictionary_csv = list(csv.DictReader(source1_csv))


          But if your csv is rather big, creating a list out of it isn't recommended, as list size will be big.



          Solution 3:



          Instead of creating a list, you can also seek the source file source1_csv to 0 before the inner loop:



          for letters in names:
          source1_csv.seek(0)
          for entry in dictionary_csv:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          It will take the source file to the start, and dictionary_csv will read it again for you.



          Edit:



          As @merlyn pointed out in below comments, that the solution 3 will not work entirely correctly, because after seeking to 0, dictionary_csv will interpret the first line of the csv (headers) as a separate data row. So, you'll have to ignore a line after seeking to 0.



          source1_csv.seek(0)
          source1_csv.readline()


          Or, re-instantiate dictionary_csv everytime you seek source1_csv (For that, you can see @merlyn's answer below).






          share|improve this answer















          Solution 1:



          From your code above, it doesn't look like that you need to iterate over the entire csv multiple times, you can just switch the loops like:



          for entry in dictionary_csv:
          for letters in names:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Switching the loop over dictionary_csv to outer loop will avoid looping over csv multiple times.



          Solution 2:



          But if you don't want to change the order of loops, you can simply convert the DictReader to list before consuming it yourself. This way, list will consume the reader, and return you a list of it, and you can iterate over it multiple times:



          dictionary_csv = list(csv.DictReader(source1_csv))


          But if your csv is rather big, creating a list out of it isn't recommended, as list size will be big.



          Solution 3:



          Instead of creating a list, you can also seek the source file source1_csv to 0 before the inner loop:



          for letters in names:
          source1_csv.seek(0)
          for entry in dictionary_csv:
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          It will take the source file to the start, and dictionary_csv will read it again for you.



          Edit:



          As @merlyn pointed out in below comments, that the solution 3 will not work entirely correctly, because after seeking to 0, dictionary_csv will interpret the first line of the csv (headers) as a separate data row. So, you'll have to ignore a line after seeking to 0.



          source1_csv.seek(0)
          source1_csv.readline()


          Or, re-instantiate dictionary_csv everytime you seek source1_csv (For that, you can see @merlyn's answer below).







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 15 '18 at 7:22

























          answered Nov 15 '18 at 6:33









          Muhammad AhmadMuhammad Ahmad

          2,1321422




          2,1321422













          • Thanks! It works once I cast it as list. Is there a way to iterate or reset the "index pointer" of the dictionary? Just curious to know if there is a way to do so.

            – heyjude
            Nov 15 '18 at 6:42






          • 1





            Yes, there is a way, you'll actually have to seek source1_csv to 0, and DictReader will read it again for you.

            – Muhammad Ahmad
            Nov 15 '18 at 6:47








          • 1





            @MuhammadAhmad There's a small bug in solution 3. If dictionary_csv is not re-instantiated every time you seek the start of the file, it will interpret the headers of the csv file as regular entries.

            – merlyn
            Nov 15 '18 at 7:09











          • Yes, thanks for pointing it out. I didn't notice it before. Let me just correct it.

            – Muhammad Ahmad
            Nov 15 '18 at 7:14











          • @merlyn Corrected. Thanks. You were right about dictionary_csv taking the row of headers as a separate data row, but instead of re-instantiating it, another variant could be to ignore the first line.

            – Muhammad Ahmad
            Nov 15 '18 at 7:17





















          • Thanks! It works once I cast it as list. Is there a way to iterate or reset the "index pointer" of the dictionary? Just curious to know if there is a way to do so.

            – heyjude
            Nov 15 '18 at 6:42






          • 1





            Yes, there is a way, you'll actually have to seek source1_csv to 0, and DictReader will read it again for you.

            – Muhammad Ahmad
            Nov 15 '18 at 6:47








          • 1





            @MuhammadAhmad There's a small bug in solution 3. If dictionary_csv is not re-instantiated every time you seek the start of the file, it will interpret the headers of the csv file as regular entries.

            – merlyn
            Nov 15 '18 at 7:09











          • Yes, thanks for pointing it out. I didn't notice it before. Let me just correct it.

            – Muhammad Ahmad
            Nov 15 '18 at 7:14











          • @merlyn Corrected. Thanks. You were right about dictionary_csv taking the row of headers as a separate data row, but instead of re-instantiating it, another variant could be to ignore the first line.

            – Muhammad Ahmad
            Nov 15 '18 at 7:17



















          Thanks! It works once I cast it as list. Is there a way to iterate or reset the "index pointer" of the dictionary? Just curious to know if there is a way to do so.

          – heyjude
          Nov 15 '18 at 6:42





          Thanks! It works once I cast it as list. Is there a way to iterate or reset the "index pointer" of the dictionary? Just curious to know if there is a way to do so.

          – heyjude
          Nov 15 '18 at 6:42




          1




          1





          Yes, there is a way, you'll actually have to seek source1_csv to 0, and DictReader will read it again for you.

          – Muhammad Ahmad
          Nov 15 '18 at 6:47







          Yes, there is a way, you'll actually have to seek source1_csv to 0, and DictReader will read it again for you.

          – Muhammad Ahmad
          Nov 15 '18 at 6:47






          1




          1





          @MuhammadAhmad There's a small bug in solution 3. If dictionary_csv is not re-instantiated every time you seek the start of the file, it will interpret the headers of the csv file as regular entries.

          – merlyn
          Nov 15 '18 at 7:09





          @MuhammadAhmad There's a small bug in solution 3. If dictionary_csv is not re-instantiated every time you seek the start of the file, it will interpret the headers of the csv file as regular entries.

          – merlyn
          Nov 15 '18 at 7:09













          Yes, thanks for pointing it out. I didn't notice it before. Let me just correct it.

          – Muhammad Ahmad
          Nov 15 '18 at 7:14





          Yes, thanks for pointing it out. I didn't notice it before. Let me just correct it.

          – Muhammad Ahmad
          Nov 15 '18 at 7:14













          @merlyn Corrected. Thanks. You were right about dictionary_csv taking the row of headers as a separate data row, but instead of re-instantiating it, another variant could be to ignore the first line.

          – Muhammad Ahmad
          Nov 15 '18 at 7:17







          @merlyn Corrected. Thanks. You were right about dictionary_csv taking the row of headers as a separate data row, but instead of re-instantiating it, another variant could be to ignore the first line.

          – Muhammad Ahmad
          Nov 15 '18 at 7:17















          2














          csv doesn't provide a way to reset the iterator but the file object interface does. You can reset a file to it's starting position using file.seek(0).



          names = ['a', 'b', 'c', 'd', 'e', 'f']
          source1_csv = open("output.csv", mode='r')

          for letters in names:
          source1_csv.seek(0)
          for entry in csv.DictReader(source1_csv):
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Of course, you can also store the entries in a list and iterate on the as many time as you want. But that won't with files too large to store in memory.






          share|improve this answer
























          • Excellent, thanks for the answer and clarification!

            – heyjude
            Nov 15 '18 at 18:49
















          2














          csv doesn't provide a way to reset the iterator but the file object interface does. You can reset a file to it's starting position using file.seek(0).



          names = ['a', 'b', 'c', 'd', 'e', 'f']
          source1_csv = open("output.csv", mode='r')

          for letters in names:
          source1_csv.seek(0)
          for entry in csv.DictReader(source1_csv):
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Of course, you can also store the entries in a list and iterate on the as many time as you want. But that won't with files too large to store in memory.






          share|improve this answer
























          • Excellent, thanks for the answer and clarification!

            – heyjude
            Nov 15 '18 at 18:49














          2












          2








          2







          csv doesn't provide a way to reset the iterator but the file object interface does. You can reset a file to it's starting position using file.seek(0).



          names = ['a', 'b', 'c', 'd', 'e', 'f']
          source1_csv = open("output.csv", mode='r')

          for letters in names:
          source1_csv.seek(0)
          for entry in csv.DictReader(source1_csv):
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Of course, you can also store the entries in a list and iterate on the as many time as you want. But that won't with files too large to store in memory.






          share|improve this answer













          csv doesn't provide a way to reset the iterator but the file object interface does. You can reset a file to it's starting position using file.seek(0).



          names = ['a', 'b', 'c', 'd', 'e', 'f']
          source1_csv = open("output.csv", mode='r')

          for letters in names:
          source1_csv.seek(0)
          for entry in csv.DictReader(source1_csv):
          print(entry["name"])
          if entry['name'] == letters:
          print("found it")


          Of course, you can also store the entries in a list and iterate on the as many time as you want. But that won't with files too large to store in memory.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 15 '18 at 6:43









          merlynmerlyn

          1,73011222




          1,73011222













          • Excellent, thanks for the answer and clarification!

            – heyjude
            Nov 15 '18 at 18:49



















          • Excellent, thanks for the answer and clarification!

            – heyjude
            Nov 15 '18 at 18:49

















          Excellent, thanks for the answer and clarification!

          – heyjude
          Nov 15 '18 at 18:49





          Excellent, thanks for the answer and clarification!

          – heyjude
          Nov 15 '18 at 18:49


















          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%2f53313567%2fcsv-dictionary-does-not-reset-to-the-beginning-when-looping-through-it-multiple%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

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python