简体   繁体   中英

Fast sorting of tuples with unsorted content into chains

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:

def chainEdges(edges):
    # make chains of edges along their connections
    chain = [min(edges, key=lambda edge: edge.index)]
    edges.remove(chain[-1])
    nodesSorted = list(chain[-1].nodes)
    while len(edges)>0:
        for edge in edges[:]:
            if nodesSorted[0] in edge.nodes:
                chain.insert(0,edge)
                edges.remove(edge)
                nodesSorted.insert(0,edge.nodes[0] if nodesSorted[0]==edge.nodes[1] else edge.nodes[1])
                if nodesSorted[0] in nodesSorted[1:-1] or (nodesSorted[0]==nodesSorted[-1] and len(edges)>0): chain = [False]# the edges connect in a non-linear manner (Y-formation)
                break
            elif nodesSorted[-1] in edge.nodes:
                chain.append(edge)
                edges.remove(edge)
                nodesSorted.append(edge.nodes[0] if nodesSorted[-1]==edge.nodes[1] else edge.nodes[1])
                if nodesSorted[-1] in nodesSorted[1:-1]: chain = [False]# the edges connect in a non-linear manner (Y-formation)
                break
        else: chain = [False]# the edges connect in a non-linear manner (Y-formation)
        if chain == [False]: break
    return chain

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM