哈希的数组哈希(autovivification ??)

时间:2014-02-11 11:01:04

标签: ruby arrays hash

我已经做了很长一段时间了,因此这让我感到困惑。我收集了来自不同地方的数据,并希望提供以下格式:

{
   :"user_100" => {
      :user_policy => [
         "userpolicy_100",
         "userpolicy_200"
      ],
      :group_policy => [
         "grouppolicy_300",
         "grouppolicy_400"
      ],
   },
   :"user_200" => {
      :user_policy => [
         "userpolicy_300",
         "userpolicy_400"
      ],
      :group_policy => [
         "grouppolicy_300",
         "grouppolicy_400"
      ],
   },
}

上面的结构是数组哈希的哈希,我只是无法在ruby中使用它。顺便说一句,我手动编写了上面的代码,因此可能存在语法错误。

我试过了:

hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }

但这只有在我有nested hashesno array的情况下才有效。

然后我尝试了:

hash = Hash.new{ |h,k| h[k] = [] }

但这仅适用于hash of arrays,而不适用于hash of hash of array

我需要在一个地方捕获这些数据,我想象它会按照上面的代码片段显示。

问题:

  1. 如何在ruby中创建hash of hash of array
  2. 是否有更通用的方法来初始化任何深度嵌套的散列/数组组合?
  3. 或者我不是以RUBY的方式思考,是否有更好的方法来解决我的根本问题?
  4. 更新

    这是我的实际代码:

    array_users = Array.new
    hash_user_polices = Hash.new{ |h,k| h[k] = [] }
    
    iam = Aws::IAM.new
    
    iam.list_users().each do |resp|
      resp.users.each do |x|
        array_users << x.user_name
      end
    end
    
    array_users.each do |user|
      iam.list_user_policies(:user_name => user).each do |resp|
        resp.each do |x|
          x.policy_names.each do |y|
            hash_user_polices[:"#{user}"] << y.to_s
          end
        end
      end
    end
    

    所以,

    1. 我获取了用户列表并将其放入array_users。然后我得到相应的用户政策,这些政策以array的形式返回(因此我正在迭代x.policy_names.each do |y|)。

    2. 我真的很想hash_user_polices[:"#{user}"][:user_policy] << y.to_s

    3. 但由于我在ruby方面的专业知识有限,我只能在hash_user_polices[:"#{user}"] << y.to_s定义hash_user_polices = Hash.new{ |h,k| h[k] = [] }之后才能使其工作。

    4. 我将编写一段单独的代码来获取group_policies,因此在那时,我希望它有hash_user_polices[:"#{user}"][:group_policy] << y.to_s

    5. 简而言之,我在三个不同的API调用中提取user listuser policygroup policy,并努力在一个地方合并这三个,以便我能够理解它的。

4 个答案:

答案 0 :(得分:1)

你可以这样做(但不知道你的数据是如何构建的,很难说)

iam = Aws::IAM.new

array_users = iam.list_users.map(&:users).flatten.map(&:user_name)

Hash[
  array_users.map do |user|
    [
      user.to_sym,
      { user_policy: iam.list_user_policies(:user_name => user).map(&:resp).flatten.map(&:policy_names).flatten.map(&:to_s),
        group_policy: <group_policy logic>
      }
    [        
  end
end ]

答案 1 :(得分:1)

如果结构总是hash.hash.array,您可以使用两次尝试的组合:

hash = Hash.new do |oh,ok|
  oh[ok] = Hash.new do |ih,ik|
    ih[ik] = []
  end
end

我个人不会使用哈希和阵列来做这件事; ruby有一个非常强大的对象模型,我会为每个嵌套级别创建类(特别是“用户”级别,它似乎有一组明确定义的属性)。不过,你可能会觉得有点矫枉过正。

答案 2 :(得分:1)

如果你的代码变得容易理解,你可以将代码拆分成更容易理解的东西吗?

def add_policy(hash, user, policy)
  # create a subhash for the user key if the hash doesn't exist
  hash[user] ||= {}

  # get the policy key: :group_policy or :user_policy
  # if policy_key can not be determined from the policy, 
  # you could pass an extra param for the policy_key
  policy_key = ( policy.include?("group") ? :group_policy : :user_policy )

  # create an array for the user's policy if none exists
  hash[user][policy_key] ||= []

  # push the policy into the array
  hash[user][policy_key] << policy

  hash
end



h = {}
add_policy(h, "user_100", "userpolicy_100")
add_policy(h, "user_100", "userpolicy_200")
add_policy(h, "user_100", "grouppolicy_300")
add_policy(h, "user_100", "grouppolicy_400")
add_policy(h, "user_200", "userpolicy_300")
add_policy(h, "user_200", "userpolicy_400")
add_policy(h, "user_200", "grouppolicy_300")
add_policy(h, "user_200", "grouppolicy_400")

=> {"user_100"=>
  {:user_policy=>["userpolicy_100", "userpolicy_200"],
   :group_policy=>["grouppolicy_300", "grouppolicy_400"]},
 "user_200"=>
  {:user_policy=>["userpolicy_300", "userpolicy_400"],
   :group_policy=>["grouppolicy_300", "grouppolicy_400"]}}

答案 3 :(得分:0)

require 'xkeys'

r={}.extend XKeys::Auto
r[:user_100, :user_policy, :[]] = 'userpolicy_100'
r[:user_100, :user_policy, :[]] = 'userpolicy_200'
r[:user_100, :group_policy, :[]] = 'grouppolicy_300'
r[:user_100, :group_policy, :[]] = 'grouppolicy_400'
r[:user_200, :user_policy, :[]] = 'userpolicy_300'
r[:user_200, :user_policy, :[]] = 'userpolicy_400'
r[:user_200, :group_policy, :[]] = 'grouppolicy_300'
r[:user_200, :group_policy, :[]] = 'grouppolicy_400'
p r
# {
#   :user_100=>{
#     :user_policy=>["userpolicy_100", "userpolicy_200"],
#     :group_policy=>["grouppolicy_300", "grouppolicy_400"]
#   },
#   :user_200=>{
#     :user_policy=>["userpolicy_300", "userpolicy_400"],
#     :group_policy=>["grouppolicy_300", "grouppolicy_400"]
#   }
# }