严重依赖Ruby数组重新排序

时间:2013-05-31 17:35:19

标签: ruby arrays

我需要根据依赖元素重新排序数组。如果一个元素是一个数组(具有依赖性),那么该数组的第二个元素就是依赖项,并且需要在该数组之前。然后删除所有依赖关系信息,因为我们不再需要,我们返回一个更正顺序的数组。

# array1 = [['a'], ['b','c'], ['c','a']]
# ordered = ['a', 'c', 'b']
# logic: c comes before b, a comes before c

以下是我认为过度设计的方法:

array1.each_with_index do |ar, i|
  # ignore elements without dependencies
  if ar.count > 1
    # get dependency
    dep = ar[1]

    # get index for element where this dependency is first
    dep_index = array1.index { |a| a.first == dep }

    # remove found dependency and store
    dep_element = array1.delete_at(dep_index)

    # insert found dependency to before current element
    array1.insert(i, dep_element)

    # delete processed dependency
    ar.delete(dep)
  end
end

上面显而易见的问题是,当我遍历数组时,具有我尚未处理的依赖关系的元素将被移回,但循环将只执行一次。所以,我介绍了一个while

while array1.flatten.count > array1.count

但是,我的结果是['c', 'a', 'b']

我还负责测试自引用和循环(无限)依赖循环。我应该使用一个枚举器吗?我应该将数组转换为不同的结构(对象)以便更轻松地管理订单吗?

2 个答案:

答案 0 :(得分:5)

查看随Ruby标准库提供的TSort

它执行拓扑排序,听起来就像你需要的那样。使用上面的示例:

require 'tsort'

class Hash
  include TSort
  alias tsort_each_node each_key
  def tsort_each_child(node, &block)
    fetch(node).each(&block)
  end
end

def deps arr
  arr.map { |head, *tail| {head => tail} }.reduce(&:merge).tsort
end

deps [['a'], ['b','c'], ['c','a']]
#=> ['a', 'c', 'b']

答案 1 :(得分:2)

无需重新发明轮子,使用Rake:

require 'rake'

ary = [[:a], [:b, :c], [:c, :a]]

ordered = []
ary.each { |head, *tail| task head => tail do ordered << head end }
task( main: ary.map( &:first ) ).invoke

ordered
#=> [:a, :c, :b]

否则,有一个算法,但我忘了它的名字。