【问题标题】:What is the most efficient way to collect arrays of nested hash keys that access the leaf-nodes?收集访问叶节点的嵌套哈希键数组的最有效方法是什么?
【发布时间】:2012-03-13 11:48:31
【问题描述】:

我有一个嵌套散列,想要一个数组,其中每个元素都是一个键数组,表示通过嵌套散列到非散列(叶节点)的路径。

例如,给定输入:

x = Hash.new
x["a"] = Hash.new
x["a"]["b"] = Hash.new
x["a"]["b"]["c"] = "one"
x["a"]["b"]["d"] = "two"
x["a"]["e"] = "three"
x["f"] = Hash.new
x["f"]["g"] = "four"

我想要输出:

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

下面的代码使用两种递归方法工作:一种用于生成嵌套数组,另一种用于取消嵌套!。

我的 Ruby 直觉告诉我,必须有一种更高效、更优雅的方式来实现这一点。任何人都可以提出“高尔夫”解决方案或完美的 Ruby Way 解决方案吗?

def collect_key_paths(object, path=[])
  result = nil
  if object.is_a?(Hash)
    path_for_current_hash = object.map do |key, value|
      incremented_path = [path, key].flatten
      collect_key_paths(value, incremented_path)
    end
    result = path_for_current_hash
  else
    result = path
  end
  result
end

def smoothe(array, store=[])
  if array.none? { |element| element.is_a?(Array) }
    store << array
  else
    array.each do |element|
      store = smoothe(element, store)
    end
  end
  store
end


x = Hash.new
x["a"] = Hash.new
x["a"]["b"] = Hash.new
x["a"]["b"]["c"] = "one"
x["a"]["b"]["d"] = "two"
x["a"]["e"] = "three"
x["f"] = Hash.new
x["f"]["g"] = "four"

nested_key_paths = collect_key_paths(x)
puts "RESULT:#{smoothe(nested_key_paths)}"

这段代码运行1.9.2版本的结果是:

RESULT:[["a", "b", "c"], ["a", "b", "d"], ["a", "e"], ["f", "g"]]

谢谢!

【问题讨论】:

标签: ruby recursion hash nested key


【解决方案1】:

我不确定这是否是“最佳”方式,但您可以避免循环两次以“平滑”结果:

def collect_key_paths(hash, path = [])
  items = []
  hash.each do |k, v|
    if v.is_a?(Hash) 
      items.push(*collect_key_paths(v, path + [k]))
    else
      items << (path + [k])
    end
  end
  items
end

p collect_key_paths(x)

【讨论】:

    【解决方案2】:
    class Hash
      def collect_key_paths(path=[])
        self.each.with_object([]) do |(k, v), a|
          if v.kind_of?(Hash)
            a.push(*v.collect_key_paths(path + [k]))
          else
            a << path + [k]
          end
        end
      end
    end
    

    所以,按照你的例子:

    x = Hash.new
    x["a"] = Hash.new
    x["a"]["b"] = Hash.new
    x["a"]["b"]["c"] = "one"
    x["a"]["b"]["d"] = "two"
    x["a"]["e"] = "three"
    x["f"] = Hash.new
    x["f"]["g"] = "four"
    
    puts x.collect_key_paths.inspect
    

    【讨论】:

      【解决方案3】:

      轻微变化:

      def collect_key_paths(hash)
        paths = []
        hash.each do |k, v|
          paths.concat( 
            Hash === v ? 
              collect_key_paths(v).map{ |path| [k, *path]} : 
              [k] 
          )
        end
        paths
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-30
        • 2020-07-07
        • 2013-12-06
        • 1970-01-01
        • 2013-03-22
        • 1970-01-01
        • 2015-12-02
        相关资源
        最近更新 更多