Most efficient way to find spatial order from a list of tuples (Python)
$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.
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 ?
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
New contributor
$endgroup$
add a comment |
$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.
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 ?
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
New contributor
$endgroup$
add a comment |
$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.
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 ?
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
New contributor
$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.
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 ?
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
python python-2.x sorting recursion
New contributor
New contributor
edited 8 hours ago
solub
New contributor
asked 8 hours ago
solubsolub
1134
1134
New contributor
New contributor
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$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 😁
$endgroup$
$begingroup$
Clear and comprehensive answer. Thank you.
$endgroup$
– solub
5 hours ago
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
$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 😁
$endgroup$
$begingroup$
Clear and comprehensive answer. Thank you.
$endgroup$
– solub
5 hours ago
add a comment |
$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 😁
$endgroup$
$begingroup$
Clear and comprehensive answer. Thank you.
$endgroup$
– solub
5 hours ago
add a comment |
$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 😁
$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 😁
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
add a comment |
$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
add a comment |
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.
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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