嵌套在散列数组中的元素的位置

时间:2013-12-19 00:51:33

标签: ruby arrays recursion hash

我有一个哈希数组,其值是哈希数组:

org_array = []
#Create Parents
org_array.push(:org_name => "Parent 1", :org_id => "123ABC", :org_parent_id => nil,     :children => [], :status => "created")
org_array.push(:org_name => "Parent 2", :org_id => "456ABC", :org_parent_id => nil, :children => [], :status => "created")
org_array.push(:org_name => "Parent 3", :org_id => "789ABC", :org_parent_id => nil, :children => [], :status => "created")
org_array.push(:org_name => "Parent 4", :org_id => "1011ABC", :org_parent_id => nil, :children => [], :status => "created")
#Create Children
org_array[0][:children].push(:org_name => "Child1", :org_id => "1234ABC", :org_parent_id => "123ABC", :children => [], :status => "created")
org_array[0][:children].push(:org_name => "Child2", :org_id => "5678ABC", :org_parent_id => "123ABC", :children => [], :status => "created")
org_array[0][:children].push(:org_name => "Child3", :org_id => "91011ABC", :org_parent_id => "123ABC", :children => [], :status => "created")
org_array[1][:children].push(:org_name => "Child1", :org_id => "1213ABC", :org_parent_id => "456ABC", :children => [], :status => "created")
org_array[1][:children].push(:org_name => "Child2", :org_id => "1415ABC", :org_parent_id => "456ABC", :children => [], :status => "created")
#Create Grandchildren
org_array[0][:children][0][:children].push(:org_name => "Granchild1", :org_id => "1617ABC", :org_parent_id => "1234ABC", :children => [], :status => "created")
org_array[0][:children][1][:children].push(:org_name => "Granchild2", :org_id => "1617ABC", :org_parent_id => "5678ABC", :children => [], :status => "created")
org_array[0][:children][2][:children].push(:org_name => "Granchild3", :org_id => "1819ABC", :org_parent_id => "91011ABC", :children => [], :status => "created")
org_array[1][:children][0][:children].push(:org_name => "Granchild1", :org_id => "1920ABC", :org_parent_id => "1213ABC", :children => [], :status => "created")
org_array[1][:children][1][:children].push(:org_name => "Granchild2", :org_id => "2122ABC", :org_parent_id => "1415ABC", :children => [], :status => "created")

以下代码返回对象和密钥:

def nested_hash_value(obj, key, value)
  if obj.respond_to?(:key?) && obj.key?(key) && obj.has_value?(value)
    return obj[key]
  elsif obj.respond_to?(:each)#checks to see if its an array
    r = nil
    obj.find{ |*a|r=nested_hash_value(a.last ,key, value)}
    r
  end
end

nested_hash_value(org_array, :org_id, "2122ABC")

但我希望它返回对象的位置,例如org_array[1][:children][1][:children][0]而不是2122ABC的值。

2 个答案:

答案 0 :(得分:1)

def nested_hash_value(arr, key, val, path_arr = [])
  return nil if arr.empty?
  arr.each_with_index do |h,i|    
    return path_arr << i if h.key?(key) && h[key] == val
    if h.key?(:children) && rv = nested_hash_value(arr[i][:children], \
        key, val, path_arr.dup << i << :children)
      return rv
    end        
  end
  return nil
end  

p nested_hash_value(org_array, :org_id, "2122ABC")
  # => [1, :children, 1, :children, 0]
p nested_hash_value(org_array, :org_id, "1819ABC")
  # => [0, :children, 2, :children, 0]
p nested_hash_value(org_array, :org_id, "789ABC")
  # => [2]
p nested_hash_value(org_array, :org_id, "91011ABC")
 # => [0, :children, 2]

由于您是Stackoverflow(SO)的新手,我想就您的问题的制定提出一些建议,您可能希望将来适用这些建议:

  • 删除不是问题核心的所有哈希字段;
  • 将儿童和孙子女的数量减少到插图所需的最低数量;和
  • 而不是显示构造数组的代码,以一种澄清其结构的方式显示数组本身。

应用这些原则,您可以从以下内容开始:

org_array =
  [{:org_id=>"123ABC", :org_parent_id => nil, :children =>
      [{:org_id=>"1234ABC", :org_parent_id=>"123ABC", :children =>
          [{:org_id=>"1617ABC", :org_parent_id=>"1234ABC", :children => []}]
        },
        {:org_id=>"5678ABC", :org_parent_id=>"123ABC", :children =>
          [{:org_id=>"1617ABC", :org_parent_id=>"5678ABC", :children => []}]
        }
      ]
    },
    {:org_id=>"456ABC", :org_parent_id => nil, :children =>
      [{:org_id=>"1213ABC", :org_parent_id=>"456ABC", :children =>
          [{:org_id=>"1920ABC", :org_parent_id=>"1213ABC", :children => []}]
        },
        {:org_id=>"1415ABC", :org_parent_id=>"456ABC", :children =>
          [{:org_id=>"2122ABC", :org_parent_id=>"1415ABC", :children => []}]
        }
      ]
    }
  ]

如果完全使用水平滚动线条太长而无法显示,请插入线条延续字符。如果没有继续,假装这条线很长:

   {:org_id => "1415ABC", :org_parent_id => "456ABC", \
      :children =>

您可以考虑在代码中定义orig_arr,而不是使用所有推送语句(当然,除非它是动态构造的)。

现在让我们考虑更改数组org_array的结构是否有帮助。考虑到数组索引确实没有用处,你可以考虑使用散列键:org_id使其成为哈希散列的哈希值。 (注意,Grandchild1和Grandchild2具有相同的:org_id。这不是问题,因为他们的父母(Child1和Child2)有不同的密钥,但我不知道你是否打算这样做。)

对父ID的反向引用通常不是必需的,因为后者在您需要时可用,或者可以在运行中轻松计算。您可以考虑使用以下哈希值,其中包含org_array中的所有信息字段:

org_hash =
  {"123ABC" => {:org_name => "Parent 1", :status => "created", :children =>
     {"1234ABC" => {:org_name => "Child1", :status => "created", :children => 
        {"1617ABC" => {:org_name => "Grandchild1", :status => "created"}}},
      "5678ABC" => {:org_name => "Child2", :status => "created", :children =>
        {"1617ABC" => {:org_name => "Grandchild2", :status => "created"}}}}},
   "456ABC" => {:org_name => "Parent 2", :status => "created", :children =>
     {"1213ABC" => {:org_name => "Child1", :status => "created", :children => 
        {"1920ABC" => {:org_name => "Grandchild1", :status => "created"}}},
      "1415ABC" => {:org_name => "Child2", :status => "created", :children =>
        {"2122ABC" => {:org_name => "Grandchild2", :status => "created"}}}}}
  }  

这样定义org_hash会让您的生活更轻松吗?

顺便说一句,您可能会熟悉一种“漂亮印刷”宝石,它可以对复杂对象(如org_arrayorg_hash)进行格式化。一个这样的宝石是Awesome Print,您可以按如下方式调用:

require 'ap'
ap org_hash

它将显示以下内容(我在父1之后截断):

{
    "123ABC" => {
        :org_name => "Parent 1",
          :status => "created",
        :children => {
            "1234ABC" => {
                :org_name => "Child1",
                  :status => "created",
                :children => {
                    "1617ABC" => {
                        :org_name => "Grandchild1",
                          :status => "created"
                    }
                }
            },
            "5678ABC" => {
                :org_name => "Child2",
                  :status => "created",
                :children => {
                    "1617ABC" => {
                        :org_name => "Grandchild2",
                          :status => "created"
                    }
                }
            }
        }
    },
...

答案 1 :(得分:0)

我认为你应该考虑传递在数据结构中产生当前“位置”所需的密钥

def nested_hash_value(obj, key, value, keychain=[])
  keychain << key

  if obj.respond_to?(:key?) && obj.key?(key) && obj.has_value?(value)
    return keychain
  elsif obj.respond_to?(:each)  # checks to see if its an array
    r = nil
    obj.find{ |*a| r=nested_hash_value(a.last ,key, value, keychain) }
    r
  end
end

nhv_result = nested_hash_value(org_array, :org_id, "2122ABC")

注意:我认为这会输出类似

的内容
#=> nhv_result
[1, :children, 1, :children, 0]

但它还没有。我正在进行改进,但这显然是一种可行的方法


然后您的结果是如何再次找到该值的描述符

nhv_result.reduce(org_array) {|acc, key| acc = acc[key] }