Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 将散列深度转换为路径的平面数组_Ruby On Rails_Ruby - Fatal编程技术网

Ruby on rails 将散列深度转换为路径的平面数组

Ruby on rails 将散列深度转换为路径的平面数组,ruby-on-rails,ruby,Ruby On Rails,Ruby,我想获得一些技巧和示例,说明如何转换如下不同的结构: h = { friend: [:id, :name], meta: { board: [:id, :name], column: [:id, :name, users: [:id, :name]] }, trello: [:id, :name] } [[:friend, :id], [:friend, :name], [:meta, :board, :id], [:met

我想获得一些技巧和示例,说明如何转换如下不同的结构:

h = {
    friend: [:id, :name],
    meta: {
        board: [:id, :name],
        column: [:id, :name, users: [:id, :name]]
    },
    trello: [:id, :name]
}
[[:friend, :id],
 [:friend, :name],
 [:meta, :board, :id],
 [:meta, :board, :name],
 [:meta, :column, :id],
 [:meta, :column, :name],
 [:meta, :column, :users, :id],
 [:meta, :column, :users, :name],
 [:trello, :id],
 [:trello, :name]]
如下所示进入阵列:

h = {
    friend: [:id, :name],
    meta: {
        board: [:id, :name],
        column: [:id, :name, users: [:id, :name]]
    },
    trello: [:id, :name]
}
[[:friend, :id],
 [:friend, :name],
 [:meta, :board, :id],
 [:meta, :board, :name],
 [:meta, :column, :id],
 [:meta, :column, :name],
 [:meta, :column, :users, :id],
 [:meta, :column, :users, :name],
 [:trello, :id],
 [:trello, :name]]
此数组的每个元素都是完整路径。

这是非常标准的。您可以通过递归使用:

# for Array.wrap; It's needed in pure ruby script, not in Rails
require 'active_support/all'

def deep_flatten(tree, path, result)
  tree.each do |key, value|
    Array.wrap(value).each do |e|
      if e.is_a? Hash
        deep_flatten(e, path + [key], result)
      else
        result << path + [key, e]
      end
    end
  end
end

tree = {
  friend: [:id, :name],
  meta: {
    board: [:id, :name],
    column: [:id, :name, users: [:id, :name]]
  },
  trello: [:id, :name]
}

result = []
deep_flatten(tree, [], result)
result.each do |line|
  puts line.inspect
end
代码

解释

递归方法执行的操作总是很难解释。根据我的经验,最好的方法是在代码中添加puts语句。然而,这本身是不够的,因为在查看输出时,很难跟踪递归级别,在该级别上获得特定结果,方法何时调用自身,以及返回到哪个版本的自身。解决方法是缩进和取消缩进结果,这就是我在下面所做的

INDENT = 4

@col = -INDENT

def indent
  @col += INDENT
end

def undent
  @col -= INDENT
end

def pu(s)
  print " "*@col
  puts s
end
导致显示以下内容

passed obj = {:friend=>[:id, :name], :meta=>{:board=>[:id, :name],
              :column=>[:id, :name, {:users=>[:id, :name]}]}, :trello=>[:id, :name]}
processing hash...
k=friend, v=[:id, :name], a=[]
    passed obj = [:id, :name]
    processing array...
    v = id
    a = []
    v is a symbol
    v = name
    a = [:id]
    v is a symbol
    returning [:id, :name]

你尝试了什么?请澄清或删除最后一句话,并进行编辑。请注意,我将您的哈希值设置为变量h的值。这样,用户都可以在答案和评论中引用相同的变量,而无需定义它。很酷,非常感谢,这是一个了不起的解决方案!我刚刚删除了对Array.wrap的依赖关系,我完全明白了这个想法。@Renat添加了一些链接。
def doit(obj)
  begin                                                  # rem
    indent                                               # rem
    pu "passed obj = #{obj}"                             # rem   
    case obj
    when Hash
      pu "processing hash..."                            # rem
      obj.each_with_object([]) do |(k,v),a|
        pu "k=#{k}, v=#{v}, a=#{a}"
        case v
        when Symbol
          a << v
        else
          doit(v).each { |aa| a << [k, *aa] }
        end
      end
    else
      pu "processing array..."                           # rem
      obj.each_with_object([]) do |v,a|
        pu "v = #{v}"                                    # rem
        pu "a = #{a}"                                    # rem
        case v
        when Symbol
          pu "v is a symbol"                             # rem
          a << v
        else
          pu "calling doit(v). v is a hash or an array"  # rem
          doit(v).each { |aa| a << aa }
        end
      end
    end.
    tap { |o| pu "returning #{o}" }                      # rem
  ensure                                                 # rem
    undent                                               # rem
  end
end
doit(h)
passed obj = {:friend=>[:id, :name], :meta=>{:board=>[:id, :name],
              :column=>[:id, :name, {:users=>[:id, :name]}]}, :trello=>[:id, :name]}
processing hash...
k=friend, v=[:id, :name], a=[]
    passed obj = [:id, :name]
    processing array...
    v = id
    a = []
    v is a symbol
    v = name
    a = [:id]
    v is a symbol
    returning [:id, :name]
k=meta, v={:board=>[:id, :name], :column=>[:id, :name, {:users=>[:id, :name]}]},
a=[[:friend, :id], [:friend, :name]]
    passed obj = {:board=>[:id, :name],
                  :column=>[:id, :name, {:users=>[:id, :name]}]}
    processing hash...
    k=board, v=[:id, :name], a=[]
        passed obj = [:id, :name]
        processing array...
        v = id
        a = []
        v is a symbol
        v = name
        a = [:id]
        v is a symbol
       returning [:id, :name]
    k=column, v=[:id, :name, {:users=>[:id, :name]}],
    a=[[:board, :id], [:board, :name]]
        passed obj = [:id, :name, {:users=>[:id, :name]}]
        processing array...
        v = id
        a = []
        v is a symbol
        v = name
        a = [:id]
        v is a symbol
        v = {:users=>[:id, :name]}
        a = [:id, :name]
        calling doit(v). v is a hash or an array
            passed obj = {:users=>[:id, :name]}
            processing hash...
            k=users, v=[:id, :name], a=[]
                passed obj = [:id, :name]
                processing array...
                v = id
                a = []
                v is a symbol
                v = name
                a = [:id]
                v is a symbol
                returning [:id, :name]
            returning [[:users, :id], [:users, :name]]
        returning [:id, :name, [:users, :id], [:users, :name]]
    returning [[:board, :id], [:board, :name], [:column, :id], [:column, :name],     
               [:column, :users, :id], [:column, :users, :name]]
k=trello, v=[:id, :name], a=[[:friend, :id], [:friend, :name], [:meta, :board, :id],
 [:meta, :board, :name], [:meta, :column, :id], [:meta, :column, :name],
 [:meta, :column, :users, :id], [:meta, :column, :users, :name]]
    passed obj = [:id, :name]
    processing array...
    v = id
    a = []
    v is a symbol
    v = name
    a = [:id]
    v is a symbol
    returning [:id, :name]
returning [[:friend, :id], [:friend, :name], [:meta, :board, :id],
           [:meta, :board, :name], [:meta, :column, :id], [:meta, :column, :name],
           [:meta, :column, :users, :id], [:meta, :column, :users, :name],
           [:trello, :id], [:trello, :name]]
 #=> [[:friend, :id], [:friend, :name], [:meta, :board, :id], [:meta, :board, :name],
      [:meta, :column, :id], [:meta, :column, :name], [:meta, :column, :users, :id],
      [:meta, :column, :users, :name], [:trello, :id], [:trello, :name]]