Most efficient way to find spatial order from a list of tuples (Python)












2












$begingroup$


I have a circle-growth algorithm (line-growth with closed links) where new points are added between existing points at each iteration.



The linkage information of each point is stored as a tuple in a list. That list is updated iteratively.



enter image description here



QUESTIONS:




  • What would be the most efficient way to return the spatial order of these points as a list ?


  • Do I need to compute the whole order at each iteration or is there a way to cumulatively insert the new points in a orderly manner into that list ?



enter image description here



All I could come up with is the following:



tuples = [(1, 4), (2, 5), (3, 6), (1, 6), (0, 7), (3, 7), (0, 8), (2, 8), (5, 9), (4, 9)]

starting_tuple = [e for e in tuples if e[0] == 0][0]
## note: 'starting_tuple' could be either (0, 7) or (0, 8), starting direction doesn't matter

order = [starting_tuple[0], starting_tuple[1]]
## order will always start from point 0

idx = tuples.index(starting_tuple)
## index of the starting tuple


def findNext():
global idx
for i, e in enumerate(tuples):
if order[-1] in e and i != idx:
ind = e.index(order[-1])
c = 0 if ind == 1 else 1
order.append(e[c])
idx = tuples.index(e)


for i in range(len(tuples)/2):
findNext()

print order


It is working but it is neither elegant (non pythonic) nor efficient.
It seems to me that a recursive algorithm may be more suitable but unfortunately I don't know how to implement such solution.



Also, please note that I'm using Python 2 and can only have access to full python packages (no numpy).



This question has also been posted on SO.










share|improve this question









New contributor




solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$

















    2












    $begingroup$


    I have a circle-growth algorithm (line-growth with closed links) where new points are added between existing points at each iteration.



    The linkage information of each point is stored as a tuple in a list. That list is updated iteratively.



    enter image description here



    QUESTIONS:




    • What would be the most efficient way to return the spatial order of these points as a list ?


    • Do I need to compute the whole order at each iteration or is there a way to cumulatively insert the new points in a orderly manner into that list ?



    enter image description here



    All I could come up with is the following:



    tuples = [(1, 4), (2, 5), (3, 6), (1, 6), (0, 7), (3, 7), (0, 8), (2, 8), (5, 9), (4, 9)]

    starting_tuple = [e for e in tuples if e[0] == 0][0]
    ## note: 'starting_tuple' could be either (0, 7) or (0, 8), starting direction doesn't matter

    order = [starting_tuple[0], starting_tuple[1]]
    ## order will always start from point 0

    idx = tuples.index(starting_tuple)
    ## index of the starting tuple


    def findNext():
    global idx
    for i, e in enumerate(tuples):
    if order[-1] in e and i != idx:
    ind = e.index(order[-1])
    c = 0 if ind == 1 else 1
    order.append(e[c])
    idx = tuples.index(e)


    for i in range(len(tuples)/2):
    findNext()

    print order


    It is working but it is neither elegant (non pythonic) nor efficient.
    It seems to me that a recursive algorithm may be more suitable but unfortunately I don't know how to implement such solution.



    Also, please note that I'm using Python 2 and can only have access to full python packages (no numpy).



    This question has also been posted on SO.










    share|improve this question









    New contributor




    solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$















      2












      2








      2





      $begingroup$


      I have a circle-growth algorithm (line-growth with closed links) where new points are added between existing points at each iteration.



      The linkage information of each point is stored as a tuple in a list. That list is updated iteratively.



      enter image description here



      QUESTIONS:




      • What would be the most efficient way to return the spatial order of these points as a list ?


      • Do I need to compute the whole order at each iteration or is there a way to cumulatively insert the new points in a orderly manner into that list ?



      enter image description here



      All I could come up with is the following:



      tuples = [(1, 4), (2, 5), (3, 6), (1, 6), (0, 7), (3, 7), (0, 8), (2, 8), (5, 9), (4, 9)]

      starting_tuple = [e for e in tuples if e[0] == 0][0]
      ## note: 'starting_tuple' could be either (0, 7) or (0, 8), starting direction doesn't matter

      order = [starting_tuple[0], starting_tuple[1]]
      ## order will always start from point 0

      idx = tuples.index(starting_tuple)
      ## index of the starting tuple


      def findNext():
      global idx
      for i, e in enumerate(tuples):
      if order[-1] in e and i != idx:
      ind = e.index(order[-1])
      c = 0 if ind == 1 else 1
      order.append(e[c])
      idx = tuples.index(e)


      for i in range(len(tuples)/2):
      findNext()

      print order


      It is working but it is neither elegant (non pythonic) nor efficient.
      It seems to me that a recursive algorithm may be more suitable but unfortunately I don't know how to implement such solution.



      Also, please note that I'm using Python 2 and can only have access to full python packages (no numpy).



      This question has also been posted on SO.










      share|improve this question









      New contributor




      solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      I have a circle-growth algorithm (line-growth with closed links) where new points are added between existing points at each iteration.



      The linkage information of each point is stored as a tuple in a list. That list is updated iteratively.



      enter image description here



      QUESTIONS:




      • What would be the most efficient way to return the spatial order of these points as a list ?


      • Do I need to compute the whole order at each iteration or is there a way to cumulatively insert the new points in a orderly manner into that list ?



      enter image description here



      All I could come up with is the following:



      tuples = [(1, 4), (2, 5), (3, 6), (1, 6), (0, 7), (3, 7), (0, 8), (2, 8), (5, 9), (4, 9)]

      starting_tuple = [e for e in tuples if e[0] == 0][0]
      ## note: 'starting_tuple' could be either (0, 7) or (0, 8), starting direction doesn't matter

      order = [starting_tuple[0], starting_tuple[1]]
      ## order will always start from point 0

      idx = tuples.index(starting_tuple)
      ## index of the starting tuple


      def findNext():
      global idx
      for i, e in enumerate(tuples):
      if order[-1] in e and i != idx:
      ind = e.index(order[-1])
      c = 0 if ind == 1 else 1
      order.append(e[c])
      idx = tuples.index(e)


      for i in range(len(tuples)/2):
      findNext()

      print order


      It is working but it is neither elegant (non pythonic) nor efficient.
      It seems to me that a recursive algorithm may be more suitable but unfortunately I don't know how to implement such solution.



      Also, please note that I'm using Python 2 and can only have access to full python packages (no numpy).



      This question has also been posted on SO.







      python python-2.x sorting recursion






      share|improve this question









      New contributor




      solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 8 hours ago







      solub













      New contributor




      solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 8 hours ago









      solubsolub

      1134




      1134




      New contributor




      solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      solub is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          1 Answer
          1






          active

          oldest

          votes


















          1












          $begingroup$

          No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.



          In terms of efficiency (or time / space complexity), your code is $O(n^3)$ in time and $O(1)$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be $O(n^2)$ in time. The most time-efficient solution is $O(n)$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is $O(n)$ -- inferior to your original approach.



          If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.





          from collections import defaultdict

          def tuples_to_neighbors_dict(tuples):
          """
          Covert `tuples` to a dict mapping each point to a list of its neighbors.
          """
          neighbors = defaultdict(list)

          for (a,b) in tuples:
          neighbors[a].append(b)
          neighbors[b].append(a)

          return neighbors

          def tuples_to_order(tuples, start=0):
          """
          Covert `tuples` to a list of points.
          """
          neighbors = tuples_to_neighbors_dict(tuples)
          order =

          prev = None
          current = start

          while current != start or prev is None:
          # add the current value to the list
          order.append(current)

          # move to the next -- pick the neighbor which we haven't visited yet
          neigh = neighbors[current]
          new = neigh[1] if neigh[0] == prev else neigh[0]
          prev = current
          current = new

          return order




          EDIT   I just now looked at the SO question and noticed that one answer is almost identical to mine 😁






          share|improve this answer











          $endgroup$













          • $begingroup$
            Clear and comprehensive answer. Thank you.
            $endgroup$
            – solub
            5 hours ago











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          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: "196"
          };
          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: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          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
          });


          }
          });






          solub is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211723%2fmost-efficient-way-to-find-spatial-order-from-a-list-of-tuples-python%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1












          $begingroup$

          No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.



          In terms of efficiency (or time / space complexity), your code is $O(n^3)$ in time and $O(1)$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be $O(n^2)$ in time. The most time-efficient solution is $O(n)$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is $O(n)$ -- inferior to your original approach.



          If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.





          from collections import defaultdict

          def tuples_to_neighbors_dict(tuples):
          """
          Covert `tuples` to a dict mapping each point to a list of its neighbors.
          """
          neighbors = defaultdict(list)

          for (a,b) in tuples:
          neighbors[a].append(b)
          neighbors[b].append(a)

          return neighbors

          def tuples_to_order(tuples, start=0):
          """
          Covert `tuples` to a list of points.
          """
          neighbors = tuples_to_neighbors_dict(tuples)
          order =

          prev = None
          current = start

          while current != start or prev is None:
          # add the current value to the list
          order.append(current)

          # move to the next -- pick the neighbor which we haven't visited yet
          neigh = neighbors[current]
          new = neigh[1] if neigh[0] == prev else neigh[0]
          prev = current
          current = new

          return order




          EDIT   I just now looked at the SO question and noticed that one answer is almost identical to mine 😁






          share|improve this answer











          $endgroup$













          • $begingroup$
            Clear and comprehensive answer. Thank you.
            $endgroup$
            – solub
            5 hours ago
















          1












          $begingroup$

          No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.



          In terms of efficiency (or time / space complexity), your code is $O(n^3)$ in time and $O(1)$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be $O(n^2)$ in time. The most time-efficient solution is $O(n)$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is $O(n)$ -- inferior to your original approach.



          If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.





          from collections import defaultdict

          def tuples_to_neighbors_dict(tuples):
          """
          Covert `tuples` to a dict mapping each point to a list of its neighbors.
          """
          neighbors = defaultdict(list)

          for (a,b) in tuples:
          neighbors[a].append(b)
          neighbors[b].append(a)

          return neighbors

          def tuples_to_order(tuples, start=0):
          """
          Covert `tuples` to a list of points.
          """
          neighbors = tuples_to_neighbors_dict(tuples)
          order =

          prev = None
          current = start

          while current != start or prev is None:
          # add the current value to the list
          order.append(current)

          # move to the next -- pick the neighbor which we haven't visited yet
          neigh = neighbors[current]
          new = neigh[1] if neigh[0] == prev else neigh[0]
          prev = current
          current = new

          return order




          EDIT   I just now looked at the SO question and noticed that one answer is almost identical to mine 😁






          share|improve this answer











          $endgroup$













          • $begingroup$
            Clear and comprehensive answer. Thank you.
            $endgroup$
            – solub
            5 hours ago














          1












          1








          1





          $begingroup$

          No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.



          In terms of efficiency (or time / space complexity), your code is $O(n^3)$ in time and $O(1)$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be $O(n^2)$ in time. The most time-efficient solution is $O(n)$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is $O(n)$ -- inferior to your original approach.



          If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.





          from collections import defaultdict

          def tuples_to_neighbors_dict(tuples):
          """
          Covert `tuples` to a dict mapping each point to a list of its neighbors.
          """
          neighbors = defaultdict(list)

          for (a,b) in tuples:
          neighbors[a].append(b)
          neighbors[b].append(a)

          return neighbors

          def tuples_to_order(tuples, start=0):
          """
          Covert `tuples` to a list of points.
          """
          neighbors = tuples_to_neighbors_dict(tuples)
          order =

          prev = None
          current = start

          while current != start or prev is None:
          # add the current value to the list
          order.append(current)

          # move to the next -- pick the neighbor which we haven't visited yet
          neigh = neighbors[current]
          new = neigh[1] if neigh[0] == prev else neigh[0]
          prev = current
          current = new

          return order




          EDIT   I just now looked at the SO question and noticed that one answer is almost identical to mine 😁






          share|improve this answer











          $endgroup$



          No need for recursion. You may want to first convert the tuples to a dict to make it more readable. Then iterate over the dict to construct an ordered list.



          In terms of efficiency (or time / space complexity), your code is $O(n^3)$ in time and $O(1)$ in auxiliary space. Note that idx = tuples.index(e) is not necessary at all, since tuples.index(e) == i. Making use of this would allow your code to be $O(n^2)$ in time. The most time-efficient solution is $O(n)$, which is also the time complexity of the proposed solution involving a dict. However, the auxiliary space complexity of that solution is $O(n)$ -- inferior to your original approach.



          If you want to update the order after obtaining a new tuples list, you can keep the dict and iterate over the new tuples, comparing with values in the dict to see if there is any change. However, the efficiency of this approach would probably be in most cases worse than constructing a new dict from scratch.





          from collections import defaultdict

          def tuples_to_neighbors_dict(tuples):
          """
          Covert `tuples` to a dict mapping each point to a list of its neighbors.
          """
          neighbors = defaultdict(list)

          for (a,b) in tuples:
          neighbors[a].append(b)
          neighbors[b].append(a)

          return neighbors

          def tuples_to_order(tuples, start=0):
          """
          Covert `tuples` to a list of points.
          """
          neighbors = tuples_to_neighbors_dict(tuples)
          order =

          prev = None
          current = start

          while current != start or prev is None:
          # add the current value to the list
          order.append(current)

          # move to the next -- pick the neighbor which we haven't visited yet
          neigh = neighbors[current]
          new = neigh[1] if neigh[0] == prev else neigh[0]
          prev = current
          current = new

          return order




          EDIT   I just now looked at the SO question and noticed that one answer is almost identical to mine 😁







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 7 hours ago

























          answered 7 hours ago









          kyrillkyrill

          1,197319




          1,197319












          • $begingroup$
            Clear and comprehensive answer. Thank you.
            $endgroup$
            – solub
            5 hours ago


















          • $begingroup$
            Clear and comprehensive answer. Thank you.
            $endgroup$
            – solub
            5 hours ago
















          $begingroup$
          Clear and comprehensive answer. Thank you.
          $endgroup$
          – solub
          5 hours ago




          $begingroup$
          Clear and comprehensive answer. Thank you.
          $endgroup$
          – solub
          5 hours ago










          solub is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          solub is a new contributor. Be nice, and check out our Code of Conduct.













          solub is a new contributor. Be nice, and check out our Code of Conduct.












          solub is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


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


          Use MathJax to format equations. MathJax reference.


          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%2fcodereview.stackexchange.com%2fquestions%2f211723%2fmost-efficient-way-to-find-spatial-order-from-a-list-of-tuples-python%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

          Список кардиналов, возведённых папой римским Каликстом III

          Deduzione

          Mysql.sock missing - “Can't connect to local MySQL server through socket”