简体   繁体   English

从Python中的元组列表中查找路径

[英]Find path from a list of tuples in Python

I have a list of tuples of the form: 我有以下形式的元组列表:

data = [('Abe', 'Bob', '3'), 
        ('Abe', 'Frank', '5'),
        ('Abe', 'George', '4'),
        ('Carl', 'Bob', '1'),
        ('Dan', 'Carl', '2')]

This data simulates an undirected graph, where there is a connection from 'Abe' to 'Bob' of size 3. Because the graph is undirected, it also means that there is a connection from 'Bob' to 'Abe' of size 3 as well. 此数据模拟无向图,其中从'Abe'到大小为3的'Bob'之间存在联系。由于该图是无向的,因此也意味着从'Bob'到大小为3的'Abe'之间存在联系。好。

I need to show whether or not there is a connection between two inputs and what its weight is. 我需要显示两个输入之间是否存在连接及其权重。 For example, if the input was 'Abe', 'Dan', the result would return the shortest (least node hops, NOT least weight) path from 'Abe' to 'Dan' which would be Abe, Bob, Carl, Dan and the weight, 3+1+2 = 6. 例如,如果输入为“ Abe”,“ Dan”,则结果将返回从“ Abe”到“ Dan”的最短(最小节点跳,不是最不重要的权重)路径,即Abe,Bob,Carl,Dan和权重3 + 1 + 2 = 6。

I have this code which shows whether or not 'Abe' would reach 'Dan', but I don't know how to return the path. 我有这段代码显示“ Abe”是否会到达“ Dan”,但是我不知道如何返回路径。

def get_path_and_weight(data, start, end):

    reachable = [start]
    added = -1

    while added != 0:
        added = 0
        for first, second, weight in data:
            if(first in reachable) and (second not in reachable):
                reachable.append(second)
                added += 1
            if(first not in reachable) and (second in reachable): 
                reachable.append(first)
                added += 1

        if (end in reachable):
            print("YES")
            #return path
        else:
            print("NO")

There are several packages that are already developed and debugged that do this, eg, networkx 有许多已经开发和调试过的软件包可以做到这一点,例如, networkx

import networkx as nx

data = [('Abe', 'Bob', '3'), 
        ('Abe', 'Frank', '5'),
        ('Abe', 'George', '4'),
        ('Carl', 'Bob', '1'),
        ('Dan', 'Carl', '2')]

g = nx.Graph()
for e in data:
    g.add_edge(e[0], e[1], distance=int(e[2]))
>>> nx.shortest_path(g, 'Abe', 'Bob', 'distance'), nx.shortest_path_length(g, 'Abe', 'Bob', 'distance')
(['Abe', 'Bob'], 3)

You could generate all the possible paths, and sort them by weight. 您可以生成所有可能的路径,然后按权重对它们进行排序。 Note I've changed the weights in the data to be numbers, not strings: 注意我已经将数据中的权重更改为数字,而不是字符串:

data = [
    ('Abe', 'Bob', 3), 
    ('Abe', 'Frank', 5),
    ('Abe', 'George', 4),
    ('Carl', 'Bob', 1),
    ('Dan', 'Carl', 2),
]

WEIGHT = 0
NODES = slice(1, None)

def get_path_and_weight(data, start, end):

    paths = [[0, start]]
    added = True

    while added:
        added = False

        for first, second, weight in data:
            for path in paths:
                candidate = None

                if (first in path[NODES]) and (second not in path[NODES]):
                    candidate = second
                elif (first not in path[NODES]) and (second in path[NODES]):
                    candidate = first

                if candidate:
                    new_path = list(path)
                    new_path.append(candidate)
                    new_path[WEIGHT] += weight

                    if new_path not in paths:
                        paths.append(new_path)
                        added = True

    for path in sorted(paths):
        if end in path[NODES]:
            return path

    return None

You can then call this something like: 然后,您可以将其称为:

weight, *path = get_path_and_weight(data, "Abe", "Dan")

print(path, "with weight", weight)

Gives the result: 给出结果:

['Abe', 'Bob', 'Carl', 'Dan'] with weight 6

And since it returns a path or None , you can still use it as predicate function as well: 并且由于它返回路径或None ,因此您仍然可以将其用作谓词函数:

if get_path_and_weight(data, "Abe", "Dan"):
    print("connected")
def get_rpath_with_weight(data,start,end):
    rpath = []
    reachable=False
    nxt_dst = start
    weight_ = 0
    rpath.append(nxt_dst)
    for datum in data:
        if nxt_dst in datum:
            #print datum
            fm_ = datum[0]
            to_ = datum[1]
            weight_ = weight_ + int(datum[2])
            if fm_ == nxt_dst:
               nxt_dst = to_
            else:
               nxt_dst = fm_
            if nxt_dst == end:
               reachable=True
            rpath.append(nxt_dst)
    print rpath,weight_,reachable


get_rpath_with_weight(data,'Abe','Dan')

get_rpath_with_weight(data,'Dan','Frank')

Sample Output 样本输出

['Abe', 'Bob', 'Carl', 'Dan'] 6 True
['Dan', 'Carl'] 2 False

Above example can may get path and determine if reachable, but I think you need to further enhance it to handle multiple paths too. 上面的示例可以获取路径并确定是否可访问,但是我认为您也需要进一步增强它以处理多个路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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