Ruby - 实现自定义排序

时间:2017-02-08 03:07:21

标签: ruby-on-rails ruby

我有array的{​​{1}}:

Hash

我必须首先按hash = [ { distance: 0.3997651063189804, project_id: 1, project_name: "Project 1", project_dependents_ids: [4] }, { distance: 0.414026818885287, project_id: 2, project_name: "Project 2", project_dependents_ids: [1] }, { distance: 0.6259577862775509, project_id: 3, project_name: "Project 3", project_dependents_ids: [] }, { distance: 0.43719371056189227, project_id: 4, project_name: "Project 4", project_dependents_ids: [3] }, { distance: 0.4341702282185951, project_id: 5, project_name: "Project 5", project_dependents_ids: [] } ] 对其进行排序,但如果distanceproject自我关联),则必须在{{{}之后进行排序1}} 关联

例如:

距离进行简单排序,如下所示:

project_dependents

...将导致:

  • 项目3
  • 项目4
  • Project 5
  • 项目2
  • 项目1

但这个结果不是我想要的100%。我想通过project对它进行排序。例如:

结果必须是:

  • 项目3
  • 项目4
  • Project 5
  • 项目1#项目1距离较短,但项目2依赖于它。
  • 项目2

这只是一个简单的示例。一个项目可以有很多自我关联ID等等。

所以,我想知道如何实现这种排序。也许一般的想法会有所帮助。我在这里做的所有实现都得到了巨大的代码和不正确的结果。

1 个答案:

答案 0 :(得分:3)

如果没有distance要求,Ruby的TSort就是这项工作的工具。但是,我无法弄清楚如何在拓扑排序中添加额外的要求,所以......

一个想法是从排序的数组开始,然后通过将每个元素推过其所有依赖项来重新排列它。例如。从排序顺序开始

[3, 4, 5, 2, 1]

我们单独留下3个(没有家属),单独留下4个(其所有家属都留下),单独留下5个(没有家属),1个之后推2(因为1是其依赖性和右侧),然后单独留下1个(其所有家属都留在其中),并且单独留下2个(其所有家属都留在其中)。

如果您有循环依赖关系,这将导致无限循环。它可以防范,但我会把它作为练习留给读者:)(例如,你可以在Set推送所有节点的curr,并在{{1}时清除它}递增;如果您尝试重新推送相同的,则引发错误)

curr

编辑:所有array = hash # because your naming makes no sense :) hash = array.each.with_object({}) { |o, h| h[o[:project_id]] = o } order = array.map { |o| o[:project_id] }.sort_by { |id| -hash[id][:distance] } order.each_index do |curr| dependents = hash[order[curr]][:project_dependents_ids] max_dep_index = dependents.map { |d| order.index(d) }.max if max_dep_index&.> curr order[curr .. max_dep_index - 1], order[max_dep_index] = order[curr + 1 .. max_dep_index], order[curr] redo end end result = hash.values_at(*order) 次来电都不是非常有效,我觉得应该可以做得更好......

EDIT2:让循环更加Rubyish。