在Ruby中使用TSort重新排序和排序数组

时间:2017-07-13 22:50:50

标签: arrays ruby algorithm sorting

希望我能在Ruby中对这个特定的重新排序/排序问题获得一些帮助。

我有一个数组数组,如下:

[['b', 'f'],
['f', 'h'],
['a', 'e'],
['b', 'c'],
['b', 'd'],
['e', 'g'],
['c', 'f'],
['d', 'f'],
['f', 'g'],
['g', 'h']]

每个数组中的第二个元素必须出现在第一个元素之后,所以我想编写一个程序,将它们排序为一个如下所示的数组:

['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

我正在尝试使用Ruby内置的TSort库,我也在使用this stack overflow post

所以我这样做:

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

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

sorted = flex_sort(flex)

我有几个问题。首先,我是否走在正确的轨道上?其次,当我运行此代码时,您会注意到初始数组数组不包含带有第一个元素'h'的数组,因此当我将它们转换为哈希值并尝试运行{{1}时},我得到像.tsort这样的东西,它迫使我将key 'h' does not exist放入数组数组中,以便它不会破坏。有办法解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

fetch采用第二个参数,如果它不存在,则为默认值。

fetch(node, []).each(&block)

第二个问题是,当您将阵列&:merge放入彼此时,您将覆盖以前的值。合并的当前结果是

{"b"=>["d"], "f"=>["g"], "a"=>["e"], "e"=>["g"], "c"=>["f"], "d"=>["f"], "g"=>["h"]}

每个键只有一个值。如果您将其更改为

def flex_sort(arr)
  stuff = Hash.new { |hash, key| hash[key] = [] }
  arr.each do |head, tail|
    stuff[head] << tail
  end

  stuff.tsort.reverse
end

你的哈希看起来像

{"b"=>["f", "c", "d"], "f"=>["h", "g"], "a"=>["e"], "e"=>["g"], "c"=>["f"], "d"=>["f"], "g" =>["h"]}

现在正在运行您的tsort

["a", "e", "b", "d", "c", "f", "g", "h"]

这非常接近你想要的。不熟悉这种类型,以便知道是否有一种方法可以强迫它在别人之前选择某些键,而这种方法有多种可能性。但这至少可以让你更接近。