如何在Ruby中获取可变深Trie的键的索引位置(x,y)

如何在Ruby中获取可变深Trie的键的索引位置(x,y),ruby,xls,Ruby,Xls,我有一个Trie结构,如下所示: { "Canada"=> {"Male"=> {"Children"=>{}, "Old"=>{}, "Teenager"=>{}}, "Female"=> {"Children"=>{}, "Old"=>{}, "Teenager"=>{}} }, "France"=> {"Male"=&

我有一个Trie结构,如下所示:

{
 "Canada"=>
       {"Male"=>
            {"Children"=>{}, "Old"=>{}, "Teenager"=>{}}, 
        "Female"=>
            {"Children"=>{}, "Old"=>{}, "Teenager"=>{}}
       }, 
 "France"=>
       {"Male"=>
            {"Children"=>{}, "Old"=>{}, "Teenager"=>{}}, 
       "Female"=>
            {"Children"=>{}, "Old"=>{}, "Teenager"=>{}}}
}
我用这个程序建立的:

class Trie < Hash
  def initialize
    super
  end

  def build(string)
    string.split("::").inject(self) do |h, key|
      h[key] ||= { }
      # puts h.inspect
    end
  end
end

trie = Trie.new
trie.build('Canada::Male::Children')
trie.build('Canada::Male::Old')
trie.build('Canada::Male::Teenager')
trie.build('Canada::Female::Children')
trie.build('Canada::Female::Old')
trie.build('Canada::Female::Teenager')
trie.build('France::Male::Children')
trie.build('France::Male::Old')
trie.build('France::Male::Teenager')
trie.build('France::Female::Children')
trie.build('France::Female::Old')
trie.build('France::Female::Teenager')
puts trie.inspect
编辑\u 1:

我想从我在程序中构建的Trie中构建一个excel文件

请查看excel文件中trie中键的位置,以及单元格的合并。非常不言自明

编辑_2

这是我写的一个迭代解决方案,它只适用于深度2

# coding: utf-8
require 'open-uri'
require 'spreadsheet'

dataset = [['Date', 'Canada::Male', 'Canada::Female', 'Canada::Total', 'France::Male', 'France::Female', 'France::Total'], ['2014-05-20', '10', '20', '30', '10', '20', '30'], ['2014-05-19', '20', '20', '40', '10', '20', '30'], ['2014-05-18', '20', '20', '40', '10', '25', '35']]

column_names = dataset[0]
column_hash = Hash.new{|h,k| h[k] = []}

column_names.each do |c|
  if c.include? "::"
    key_val = c.split("::")
    key = key_val[0]
    val = key_val[1]
    column_hash[key] << val
  end
end

dummy_row = Array.new(column_names.size)

book = Spreadsheet::Workbook.new
sheet = book.create_worksheet
sheet.row(0).replace(dummy_row)
sheet.row(1).replace(dummy_row)

dataset.each_with_index do |row, i|
  next if i == 0
  sheet.row(i+1).replace(row)
end

sheet.rows[0][0] = dataset[0][0]

# col_hash_key_size =  column_hash.keys.size

column_hash.keys.each_with_index do |key,i|
  size = column_hash[key].size
  sheet.rows[0][(i*size)+1] = key
end

# sheet.merge_cells(start_row, start_col, end_row, end_col)
column_hash.keys.each_with_index do |key,i|
  size = column_hash[key].size
  sheet.merge_cells(0, (i*size)+1, 0, (i+1)*size)
end

column_hash.keys.each_with_index do |key,i|
  size = column_hash[key].size
  column_hash[key].each_with_index do |val,ind|
    sheet.rows[1][(i*size)+ind+1] = val
  end
end

book.write "test.xls"
#编码:utf-8
需要“打开uri”
需要“电子表格”
数据集=['Date','Canada::Male','Canada::Femal','Canada::Femal','Canada::Total','France::Male','France::Femal','France::Total',['2014-05-20','20','30','10','20','30','10','20','30'],['2014-05-19','20','20','40','25','35']
列名称=数据集[0]
列| hash=hash.new{| h,k | h[k]=[]
列_名称。每个do | c|
如果包括?"::"
key_val=c.split(“:”)
键=键值[0]
val=键[1]

column_hash[key]我可以想出几种方法来实现这一点,但这两种方法显然都需要递归

方法#1

def depth_and_position(h, g={}, keys = [], depth=0)
  h.each_key.with_index do |k,i|
    g[(keys + [k]).join(' < ')] = [depth,i]
    depth_and_position(h[k], g, keys + [k], depth + 1) unless h[k].empty?
  end
  g
end
计算上述散列将是简单的,因为与每个子阵列
a
(例如,
[“Canada”,“Male”,“Old”
)相关联的
深度将是
a.size-1
,并且可以通过计数轻松获得第二个参数

上述数组可按如下方式计算:

def keys(h, a=[], keys = [])
  h.each_key do |k|
    a << (keys + [k])
    keys(h[k], a, keys + [k]) unless h[k].empty?
  end
  a
end
解释

计算
键(h)
后,我们获得枚举数:

enum1 = keys(h).chunk(&:size)
  #=> #<Enumerator: #<Enumerator::Generator:0x00000101a01340>:each>
enum2 = enum1.each_with_object({})
  #=> #<Enumerator: #<Enumerator:
        #<Enumerator::Generator:0x00000101a01340>:each>:each_with_object({})>
通过传递到此枚举器,对象为空哈希(由块变量
g
表示),我们获得另一个枚举器:

enum1 = keys(h).chunk(&:size)
  #=> #<Enumerator: #<Enumerator::Generator:0x00000101a01340>:each>
enum2 = enum1.each_with_object({})
  #=> #<Enumerator: #<Enumerator:
        #<Enumerator::Generator:0x00000101a01340>:each>:each_with_object({})>
散列最初是空的,但在第一个元素被传递到块后,当然是非空的


其余部分相对简单。

这里有一个简单的递归函数,它输出电子表格中每个键的位置

def to_coords hash, x = 0, y = 0
  hash.each do |k, v|
    puts "#{x},#{y} #{k}"
    x = to_coords(v, x, y + 1)
  end
  return x + (hash.empty? ? 1 : 0)
end
对于您的示例,这将输出

0,0 Canada
0,1 Male
0,2 Children
1,2 Old
2,2 Teenager
3,1 Female
3,2 Children
4,2 Old
5,2 Teenager
6,0 France
6,1 Male
6,2 Children
7,2 Old
8,2 Teenager
9,1 Female
9,2 Children
10,2 Old
11,2 Teenager

您没有给出输入的完整示例,因此需要对其进行一些调整以适合您的应用程序。基本思想是,如果您处于底层(儿童、老人、青少年),然后每个键只移动一次,因此hash.empty是1:0。如果你不在最底层,那么迭代子灰烬会告诉你下一步要使用什么X值。

你尝试了什么?似乎每个带有_索引的
都有一点
就可以了。Keen,我建议你澄清一下输出的形式你想要。例如,我在回答中假设它是一个哈希。Keen,我现在看到你对将哈希写入电子表格的兴趣与一开始构建哈希一样。恐怕我无法帮助你进行后者。事后看来,最好将问题限制在哈希的构建上,然后单独提问e关于如何将该信息写入电子表格的问题。我希望否决票主要与您的陈述有关,“…我想从这个trie结构化哈希创建一个excel工作表(使用电子表格gem)。”,因为您引用的不是散列。我建议您编辑以使其成为散列。谢谢您的夸奖,Keen,但事实是我对Ruby的了解非常有限,我没有在实际应用中使用Ruby的经验,也不知道如何将数据写入电子表格。这里还有其他人可以帮助您处理后者,however,所以我建议你发布一个新问题,重点放在这个问题上。完成。尽管你已经从信息太少变成了信息太多。trie的东西似乎与你的问题无关,因为你的问题将应用于任何嵌套哈希。你的示例输入和示例电子表格都很有用。不清楚你在问什么:一个查找单元格位置的算法或者用完整的代码生成带有合并单元格的电子表格之类的?@KeenLearner那么你的问题太广泛了。如果你已经有了一个工作的迭代版本,为什么不能用我的递归代码替换你的迭代代码呢?我为你写了这段代码,因为这是一个有点有趣的算法问题。我对此不感兴趣所有的工作都是为你做的。请仔细比较你的示例输出和我的算法输出。如果你不能自己找出它们之间的区别,你就有一个更大的问题要解决。所以不是“让人们免费为你工作”如果你在告诉我“纠正”它之前,甚至都不能努力了解我的算法在做什么,我就没有兴趣回答你的问题。
enum2 = enum1.each_with_object({})
  #=> #<Enumerator: #<Enumerator:
        #<Enumerator::Generator:0x00000101a01340>:each>:each_with_object({})>
enum2.to_a
  #=> [[[1, [["Canada"]]], {}],
  #    [[2, [["Canada", "Male"]]], {}],
  #    [[3, [["Canada", "Male", "Children"],
  #          ["Canada", "Male", "Old"],
  #          ["Canada", "Male", "Teenager"]]], {}],
  #   ...
  #    [[3, [["France", "Female", "Children"],
  #          ["France", "Female", "Old"],
  #          ["France", "Female", "Teenager"]]], {}]]
def to_coords hash, x = 0, y = 0
  hash.each do |k, v|
    puts "#{x},#{y} #{k}"
    x = to_coords(v, x, y + 1)
  end
  return x + (hash.empty? ? 1 : 0)
end
0,0 Canada
0,1 Male
0,2 Children
1,2 Old
2,2 Teenager
3,1 Female
3,2 Children
4,2 Old
5,2 Teenager
6,0 France
6,1 Male
6,2 Children
7,2 Old
8,2 Teenager
9,1 Female
9,2 Children
10,2 Old
11,2 Teenager