I want to sort the list of tuples [(0, 9), (5, 4), (2, 9), (7, 4), (7, 2)] to result in [(0, 9), (2, 9), (7, 2), (7, 4), (5, 4)].
More specifically, I have a set of edges (line segments) that I want to connect into chains (polylines). The order of the edges is random and I want to sort them. Each edge has two nodes, the start and end points, which may or may not match their direction in the final chain. The below code works, but it is just extremely slow, especially as I have to call this function many times. In my case, the nodes are instances of a custom Node class rather than integers. On average there may be about 10 edges to connect. I have to run it in Ironpython. May I ask if there is a good way to increase the speed of this? Thank you very much!
Chris
from collections import Counter
class Edge():
def __init__(self,nodeA,nodeB,edges):
self.nodes = (nodeA,nodeB)
self.index = len(edges)
edges.append(self)
def chainEdges(edges):
# make chains of edges along their connections
nodesFlat = [node for edge in edges for node in edge.nodes]
if any(Counter(nodesFlat)[node]>2 for node in nodesFlat): return# the edges connect in a non-linear manner (Y-formation)
# find first edge
elif all(Counter(nodesFlat)[node]==2 for node in nodesFlat):# the edges connect in a loop
chain = [min(edges, key=lambda edge: edge.index)]# first edge in the loop is the one with the lowest index
edges.remove(chain[-1])
nodeLast = chain[-1].nodes[-1]
else:# edges form one polyline
chain = [min([edge for edge in edges if any(Counter(nodesFlat)[node]==1 for node in edge.nodes)], key=lambda edge: edge.index)]# first edge is the one with the lowest index
edges.remove(chain[0])
nodeLast = chain[-1].nodes[0] if Counter(nodesFlat)[chain[-1].nodes[0]]==2 else chain[-1].nodes[1]
# loop through remaining edges
while len(edges)>0:
for edge in edges:
if nodeLast in edge.nodes:
chain.append(edge)
edges.remove(edge)
nodeLast = edge.nodes[0] if nodeLast==edge.nodes[1] else edge.nodes[1]
break
return chain
edges = []
for [nodeA,nodeB] in [(0, 9), (5, 4), (2, 9), (7, 4), (7, 2)]:
Edge(nodeA,nodeB,edges)
print [edge.nodes for edge in chainEdges(edges)]
>>>[(0, 9), (2, 9), (7, 2), (7, 4), (5, 4)]
I found the problem, the slow part was how I checked for Y-formations, when more than 2 edges connect at one node. When I run the method, I have already checked that all the edges are somehow connected, but I don't know if they form a line, a circle, or a Y. The following is significantly faster: