Ruby on rails 从嵌套哈希中删除所有相似的键

Ruby on rails 从嵌套哈希中删除所有相似的键,ruby-on-rails,ruby,Ruby On Rails,Ruby,给定如下哈希: { id: 1, name: "test", children: [ { id: 1, name: "kid 1" }, { id: 2, name: "kid 2" } ] } 如何递归删除所有id键?您可以编写一个递归遍历哈希和数组的函数 def delete_recursively(thing, key_to_delete) case thing when Hash # Delete the key thing.de

给定如下哈希:

{
  id: 1,
  name: "test",
  children: [
    { id: 1, name: "kid 1" },
    { id: 2, name: "kid 2" }
  ]
}

如何递归删除所有
id
键?

您可以编写一个递归遍历哈希和数组的函数

def delete_recursively(thing, key_to_delete)
  case thing
  when Hash
    # Delete the key
    thing.delete(key_to_delete)

    # Recurse into each remaining hash value.
    thing.each_value do |value|
      delete_recursively(value, key_to_delete)
    end
  when Array
    # Recurse into each value of the array.
    thing.each do |value|
      delete_recursively(value, key_to_delete)
    end
  end
end

这可以根据需要扩展为包括其他数据类型。

这当然需要递归解决方案。下面的方法不会改变原始散列

代码

def recurse(obj, key_to_delete)
  case obj
  when Array
    obj.map { |e| recurse(e, key_to_delete) }
  else # hash
    obj.reject { |k,_| k == key_to_delete }.transform_values do |v|
      case v
      when Hash, Array
        recurse(v, key_to_delete)
      else
        v
      end
    end
  end
end
h = { id: 1, name: "test", children: [
        { id: 1, name: "kid 1" }, { id: 2, name: "kid 2", grandkids: [
            { id: 3, name: "gkid1" }] }
      ]
    }
示例

def recurse(obj, key_to_delete)
  case obj
  when Array
    obj.map { |e| recurse(e, key_to_delete) }
  else # hash
    obj.reject { |k,_| k == key_to_delete }.transform_values do |v|
      case v
      when Hash, Array
        recurse(v, key_to_delete)
      else
        v
      end
    end
  end
end
h = { id: 1, name: "test", children: [
        { id: 1, name: "kid 1" }, { id: 2, name: "kid 2", grandkids: [
            { id: 3, name: "gkid1" }] }
      ]
    }

解释

递归方法执行的操作总是很难解释。根据我的经验,最好的方法是在代码中添加puts语句。然而,这本身是不够的,因为在查看输出时,很难跟踪递归的级别,在该级别上,特定的结果是获得的,或者传递给自身,或者返回给自身的版本。解决方法是缩进和取消缩进结果,这就是我在下面所做的。请注意,我构造代码的方式和我使用的几个助手方法是相当通用的,因此这种方法可以适用于检查其他递归方法执行的操作

INDENT = 8
@col = -INDENT
def indent; @col += INDENT; end
def undent; @col -= INDENT; end
def pu(s); print " "*@col; puts s; end
def puhline; pu('-'*(70-@col)); end 


15分钟后开始。不错。
recurse(h, :id)
----------------------------------------------------------------------
passed obj = {:id=>1, :name=>"test", :children=>[{:id=>1, :name=>"kid 1"},
         {:id=>2, :name=>"kid 2", :grandkids=>[{:id=>3, :name=>"gkid1"}]}]},
       key_to_delete = id
  obj with :id removed={:name=>"test", :children=>[{:id=>1, :name=>"kid 1"},
    {:id=>2, :name=>"kid 2", :grandkids=>[{:id=>3, :name=>"gkid1"}]}]}
  in tranform_values, v=test
    keeping the literal v
  in tranform_values, v=[{:id=>1, :name=>"kid 1"},
    {:id=>2, :name=>"kid 2", :grandkids=>[{:id=>3, :name=>"gkid1"}]}]
    v is Hash or Arrary
    calling recurse([{:id=>1, :name=>"kid 1"},
      {:id=>2, :name=>"kid 2", :grandkids=>[{:id=>3, :name=>"gkid1"}]}], id)...
        --------------------------------------------------------------
        passed obj = [{:id=>1, :name=>"kid 1"},
                 {:id=>2, :name=>"kid 2", :grandkids=>[{:id=>3, :name=>"gkid1"}]}],
               key_to_delete = id
        processing Array...
          calling recurse({:id=>1, :name=>"kid 1"}, id)...
                ------------------------------------------------------
                passed obj = {:id=>1, :name=>"kid 1"}, key_to_delete = id
                  obj with :id removed={:name=>"kid 1"}
                  in tranform_values, v=kid 1
                    keeping the literal v
                returning {:name=>"kid 1"}
                ------------------------------------------------------
          calling recurse({:id=>2, :name=>"kid 2",
            :grandkids=>[{:id=>3, :name=>"gkid1"}]}, id)...
                ------------------------------------------------------
                passed obj = {:id=>2, :name=>"kid 2", :grandkids=>
                         [{:id=>3, :name=>"gkid1"}]},
                       key_to_delete = id
                  obj with :id removed={:name=>"kid 2", :grandkids=>
                    [{:id=>3, :name=>"gkid1"}]}
                  in tranform_values, v=kid 2
                    keeping the literal v
                  in tranform_values, v=[{:id=>3, :name=>"gkid1"}]
                    v is Hash or Arrary
                    calling recurse([{:id=>3, :name=>"gkid1"}], id)...
                        ----------------------------------------------
                        passed obj = [{:id=>3, :name=>"gkid1"}],
                               key_to_delete = id
                        processing Array...
                          calling recurse({:id=>3, :name=>"gkid1"}, id)...
                                --------------------------------------
                                passed obj = {:id=>3, :name=>"gkid1"},
                                       key_to_delete = id
                                  obj with :id removed={:name=>"gkid1"}
                                  in tranform_values, v=gkid1
                                    keeping the literal v
                                returning {:name=>"gkid1"}
                                --------------------------------------
                        returning [{:name=>"gkid1"}]
                        ----------------------------------------------
                returning {:name=>"kid 2", :grandkids=>[{:name=>"gkid1"}]}
                ------------------------------------------------------
        returning [{:name=>"kid 1"},
                   {:name=>"kid 2", :grandkids=>[{:name=>"gkid1"}]}]
        --------------------------------------------------------------
returning {:name=>"test", :children=>[{:name=>"kid 1"},
             {:name=>"kid 2", :grandkids=>[{:name=>"gkid1"}]}]}
----------------------------------------------------------------------
  #=> {:name=>"test", :children=>[{:name=>"kid 1"},
      {:name=>"kid 2", :grandkids=>[{:name=>"gkid1"}]}]}