我需要从一些不寻常的数据中确定父/子关系。
航班号是营销创作,它们很奇怪。航空公司X的22号航班可能是指X和Y之间的单程旅行。同一航空公司的44号航班实际上可能是指城市对之间的多次航班。例如:
Flight 44: Dallas - Paris
Flight 44: Dallas - Chicago
Flight 44: Chicago - New York
Flight 44: New York - Paris
Flight 44: Chicago - Paris
Flight 44: Dallas - New York
现实 - 这是他们工作的方式。当我从“航班号和城市对的大列表”中提取数据时,我得到了这44个航班的6种组合。我每个都有乘客数量,所以如果有10个人在达拉斯 - 巴黎飞行,我需要拿这10个乘客并将它们添加到DAL - CHI,CHI - NY和NY - PAR段。
从所有细分的列表中,我需要弄清楚“啊,这是从达拉斯飞往巴黎的航班” - 然后当我看到乘客负载时,我可以相应地增加城市到城市的实际负载像这样:
- Value associated with AD -- > increment segments AB, BC, CD
- value associated with AC --> increment only segments AB, BC
- value associated with AB --> increment only segment AB
etc.
假设我得到这样的航班44的无序值列表:(DAL-CHI,CHI-NYC,NYC-PAR,DAL-NYC,DAL-PAR,CHI-PAR)。如何计算父子结构,比较这6种组合中的这4个值?
答案 0 :(得分:4)
让a_i -> b_i
成为航班44 i
的成对列表中的i = 1..M
条目。
让V
成为所有唯一a_i
和b_i
值的集合:
V = {a_i | i = 1..M} U {b_i | i = 1..M}
让E
成为所有对(a_i, b_i)
的集合:
E = {(a_i, b_i) | i = 1..M}
然后G = (V, E)
是directed acyclic graph,其中顶点V
是城市,有向边E
对应于列表中的条目a_i -> b_i
。
您要找的是图G
的{{3}}。链接的维基百科页面具有此算法的伪代码。
这将为您提供城市的线性排序(在您的示例中:[Dallas, Chicago, New York, Paris]
),这与您的初始列表中存在的所有排序约束一致。如果您的初始列表包含少于|V| choose 2
个对(意味着没有完整的约束集),那么您的集V
中的城市可能会有多个一致的拓扑排序。
答案 1 :(得分:1)
注意:这是常识性分析,但是请参阅Timothy Shields解决方案,他将问题确定为拓扑排序问题,因此具有已知的计算复杂性和关于唯一性的已知条件。
我将尝试从您的答案中提取问题的核心,以便正式描述它。
在上面的示例中,您实际上有四个节点(城市),为简洁起见,表示为D,P,C和NY。您有一组有序对(x,y),它们被解释为“在该航班上,节点x在节点y之前”。将其写为x<y
,我们实际上有以下内容:
(对于044航班):
D < P
D < C
C < NY
NY < P
C < P
D < NY
根据这些约束,我们希望找到一个有序元组(x, y, z, w)
,使得x < y < z < w
和上述约束成立。我们知道解决方案是(x=D, y=C, z=NY, w=P)
。
注意:可能在您的数据库中,集合中的第一个元素始终是“起始 - 目标对”(在我们的示例中为D<P
)。但是,随后的分析并没有太大变化。
如何以编程方式找到这个有序的元组?我对算法有相对公平的了解,但我不知道解决这个问题的标准方法(其他用户可能会在这里提供帮助)。我担心结果的独特性。它可能是对数据完整性的良好单元测试,您应该要求该有序元组的解决方案是唯一的,否则您可能会随后增加错误的段。
当我们处理唯一性问题时,我建议生成节点的所有排列,并显示在给定约束条件下可行的所有解决方案。
天真的实现可能如下所示:
import itertools
nodes = ['D', 'P', 'NY', 'C']
result = [ot
for ot in itertools.permutations(nodes) # ot = ordered tuple
if ot.index('D') < ot.index('P')
if ot.index('D') < ot.index('C')
if ot.index('C') < ot.index('NY')
if ot.index('NY') < ot.index('P')
if ot.index('C') < ot.index('P')
if ot.index('D') < ot.index('NY')
]
print result
# displays: [('D', 'C', 'NY', 'P')]
如果节点数量较少,这种“天真”实现可能就足够了。如果数字越高,我建议以这样的方式实现它,即有效地使用约束来修剪解空间(问我是否需要提示)。
答案 2 :(得分:1)
从您的航班列表中构建所有离开或目的地城市的列表。这给了四个 城市:
Dallas
Paris
Chicago
New York
再次迭代航班列表并计算每个目的地城市的出现次数:
0 Dallas
3 Paris
1 Chicago
2 New York
按目的地计数对列表进行排序,您有路线:
Dallas -> Chicago -> New York -> Paris
注意:如果目的地计数从零开始不连续(例如,0,1,2,3 ...),则表示该航班的出发/目的地列表不一致或不完整。
答案 3 :(得分:0)
您是否考虑过使用带有列表商店的dictionary。
字典基本上是一个哈希表,你可以存储一个键(前端和终点,AD)和一个值(它需要经过[AB,BC,CD]的段)
答案 4 :(得分:0)
好的,拿两个:这是一个函数,它将采用一个字符串,例如你提供的字符串,并根据维基百科文章进行拓扑排序。
import re
import itertools
def create_nodes(segments):
remaining_segments = re.findall(r'(\w*?)-(\w*?)[,)]', segments)
nodes = []
while len(remaining_segments) > 1:
outgoing, incoming = zip(*remaining_segments)
point = next(node for node in outgoing if node not in incoming)
nodes.append(point)
remaining_segments = [segment for segment in remaining_segments if segment[0] != point]
last_segment = remaining_segments.pop()
nodes.extend(last_segment)
return nodes
测试:
>>> foo = '(DAL-CHI, CHI-NYC, NYC-PAR, DAL-NYC, DAL-PAR, CHI-PAR)'
>>> scratch.create_nodes(foo)
['DAL', 'CHI', 'NYC', 'PAR']
请注意,对于每次使用,这都不是完美的拓扑排序函数;但是,对于您的多站单程旅行的具体使用情况,它应该是有效的。