Ruby 从依赖关系图中查找并拓扑排序所有树,包括给定的节点组

Ruby 从依赖关系图中查找并拓扑排序所有树,包括给定的节点组,ruby,topological-sort,Ruby,Topological Sort,假设我有下面的依赖关系图(A=>[B]意味着A需要B更新其值,然后才能更新A的值)。我使用Ruby哈希和TSort模块进行拓扑操作 graph = { a: OpenStruct.new(dependencies: []), b: OpenStruct.new(dependencies: [:a]), c: OpenStruct.new(dependencies: [:b]), d: OpenStruct.new(dependencies: []), e: OpenStruc

假设我有下面的依赖关系图(
A=>[B]
意味着A需要B更新其值,然后才能更新A的值)。我使用Ruby哈希和TSort模块进行拓扑操作

graph = {
  a: OpenStruct.new(dependencies: []),
  b: OpenStruct.new(dependencies: [:a]),
  c: OpenStruct.new(dependencies: [:b]),
  d: OpenStruct.new(dependencies: []),
  e: OpenStruct.new(dependencies: [:d]),
  f: OpenStruct.new(dependencies: []),
}
# Which gives 3 dependency trees
:c => :b => :a, :e => :d, :f 
给定任何一组节点,我需要查找需要更新的节点并对其进行拓扑排序,包括(递归地)这组节点的父节点和子节点。也就是说,包含这些节点的所有依赖关系树,而不仅仅是树中这些节点的依赖关系

这里有一些示例(关于输出,我可以处理一个排序图数组,也可以处理一个展平版本,我不在乎,参见示例3),但是排序图数组更容易规范,如下所示

我已经尝试实现TSort算法,但我不确定如何指定还需要包括请求TSort的节点的父节点

我当前的实现(在上面给出的
图上)

def complete_function_to_get_tsorted_子图(图、节点名称)
每个_节点=lambda{|&b | graph.slice(*节点名称)。每个_键(&b)}
每个子节点=lambda do节点名称(&b)|
图形[节点名称].依赖项.每个(&b)
结束
TSort.TSort(每个节点、每个子节点)
结束
它是不完整的,因为当前它只获取请求节点的依赖项
complete\u函数\u获取被排序的子图(图,:b)#返回[:a,:b]而不是[:a,:b,:c]
如果我删除
切片
,它只会成为完整图上的一个排序,这不是我想要的(我需要对它进行某种程度的删减)

我想要实现的规范(假设我们返回的是tsorted依赖关系图数组)

expect(完成函数以获取排序子图(:b))。包括([:a,:b,:c])
expect(complete_function_to_get_tsorted_子图(:b,:d)。to
包括([:a,:b,:c],:d,:e])

我使用TSort算法的方法正确吗?你能帮我修复我的函数吗?还是我必须走一条完全不同的道路才能得到我想要的东西?

我最终做了什么:

从我需要计算的stat开始,一直到依赖性最大的叶节点(因此,如果我需要计算:b,总是假设您需要find:c),函数如下(实现很可能会得到改进)


然后使用我在问题中提到的代码从这里构建排序依赖项列表

请参见“”,以及链接的页面和“。我们需要最小的代码示例、最小的输入数据来测试它和预期的结果。@如果这还不够,管理员可以帮助我理解,但是我的问题中有具有预期结果的代码示例”“文档特别说明“确保重现问题所需的所有信息都包含在问题本身中”。这意味着它是可运行的,演示了问题,并且我们不必组装测试工具,因为您已经提供了输入和预期结果,以及出现了什么问题。我们为了让您的代码运行而编写的代码越多,我们得到的示例代码就越远,从而降低了答案的准确性和简洁性。如果我们运行了你的代码会发生什么?我做了一些简单的编辑,在图形定义中添加了缺少的右括号,并更改了我的函数接口,将图形作为第一个参数,这样你就可以在irb终端中复制粘贴代码(图形定义+函数)运行
completed\u function\u以获取排序的子图(图,:b)
将起作用。非常好。运行代码很重要,否则由于语法错误或不包含演示问题的代码,问题将脱离主题。
desired_function(:a) == [:c,:b,:a] # or [[:c,:b,:a]]
desired_function(:b) == [:c,:b,:a] # or [[:c,:b,:a]]
desired_function(:c) == [:c,:b,:a] # or [[:c,:b,:a]]
desired_function(:c,:d) == [:c,:b,:a,:d,:e] # or [:d,:e,:c,:b,:a] or [[:d,:e], [:c,:b,:a]], or [[:c,:b,:a], [:d,:e]]
desired_function(:f) == [:f] # or [[:f]]
def find_leaf_nodes(node_name)
  parents = all_nodes.select { |_,node| node.dependencies.include?(name) }
  if parents.any?
    parents.flat_map { |parent_name, _| find_leaf_nodes(parent_name) }
  else
    name
  end
end