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.

asked Jan 17, 2019 at 22:42
\$\endgroup\$

1 Answer 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 😁

answered Jan 18, 2019 at 0:07
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.