Python:比较和排序列表中的元组

时间:2017-04-18 17:01:37

标签: python list sorting tuples networkx

我正在尝试对点列表(他们的ID)进行排序。元组是图的最小生成树(使用networkx)的结果,其中每个节点都连接到每个其他节点,但它们的权重不同。我需要为每个树提取(最短)路径,这将给出正确的边缘顺序。但是MST的元组的结果是无序的,如果我按原样使用它,我会得到不好的结果,所以我需要对tupes进行排序。我有一些元组的示例列表:

L1: [(0, 1), (0, 3), (2, 3)]
L2: [(0, 3), (1, 2), (2, 3)]
L3: [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

L1和L2没有按我的要求排序,L3是。您可能会注意到,我需要列表的顺序是后续的点/元组,以获得树的顺序。 L1和L2需要按如下方式排序:

L1: [(1, 0), (0, 3), (3, 2)] : order = 1-0-3-2
L2: [(0, 3), (3, 2), (2, 1)] : order = 0-3-2-1

# some way to do this in pseudo code would be
for tuple in list:
    # compare current tuple with previous and next (if exist)
    if tuple[1] != next[0]:
        reverse tuple
    if tuple[0] != prev[1]:
        reverse tuple
    etc...

我试图通过定义多个if / elif语句(见上文)对列表进行排序,但这会变得混乱和混乱。我已经看过像sorted(L1, key=customsort)这样的东西排序,但我找不到比较多个元组的方法,我希望这样的事情是可能的!

2 个答案:

答案 0 :(得分:1)

最简单的方法是找到路径的起​​点,根据注释,它是出现一次的两个索引之一,同时构建一个连续遍历的方法。假设n节点我们可以构建一些东西来帮助我们(这个解决方案我认为是清晰的,线性的,但可能不是最好的/最优雅的):

path = [[] for _ in range(n)]
stops= [2 for _ in range(n)]
for edge in result:
    for i in range(2):
        path[edge[i]].append(edge[1-i])
        stops[edge[i]] -= 1
for current in range(len(stops)):
    if stops[current]: break

path这里保存每个索引(它是一个节点)它连接的两个/一个其他节点。内循环查看边缘中的点 - edge[0],edge[1]1-i只是将1翻转为0。

stops计算节点出现的次数。每个节点在路径中出现两次,除了两个 - 这些将是数组中唯一不是0的位置。这不是必须的,只是一个简单的起点。

current查找这样的非零条目。

现在通过遍历路径来重建,以便根据需要创建正确的元组列表:

result = [(current,path[current][0])] #Only one option!
current= path[current][0]
while stops[current]:
   next = path[current][1] if path[current][0] == current else path[current][0]
   result.append((current,next))
   current = next

注意我没有使用原始列表中的一些知识,例如订单。您可以使用它来改善这一点。

答案 1 :(得分:0)

我决定尝试改进上述答案,并使个别操作更简单。

import collections


def sort_mst(lst):
    unordered = [frozenset(elem) for elem in lst]
    elems = collections.defaultdict(set)
    for elem in unordered:
        # Assumption: elem has length 2
        for index in elem:
            # Assumption: each set will have an elem added no more than twice.
            elems[index].add(elem)
    # For theoretically faster, but non-deterministic behavior, use next()
    # instead of min()
    index = min(k for k, v in elems.items() if len(v) == 1)
    results = []
    while elems[index]:
        connection, = elems[index]
        next_index, = connection - {index}
        results.append((index, next_index))
        index = next_index
        elems[index] -= {connection}
    return results

这使用集合来丢弃不需要的订购信息。它首先将所有元组转换为集合,然后创建从索引到包含它们的集合的反向映射。

接下来,它找到一个仅与一个集相关联的索引,并使用它来遍历反向映射,在将它们添加到输出列表时从中丢弃集。当没有与索引关联的集合时,在丢弃前面的集合之后,它知道它到达另一端,并且完成了。