【问题标题】:Hash of Hash of Array (autovivification ??)Hash of Array (autovivification ??)
【发布时间】:2014-02-11 11:01:03
【问题描述】:

我已经完成 很长一段时间了,因此这让我在 感到困惑。我正在从各个地方收集以下数据,并希望采用以下格式:

{
   :"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

我需要在一个地方捕获这些数据,我想像上面代码 sn-p 中显示的那样以 perl 方式进行。

问题:

  1. 如何在 ruby​​ 中创建hash of hash of array
  2. 是否有更通用的方法来初始化任何深度嵌套的哈希/数组组合?
  3. 或者我的思维方式不是像 RUBY 那样,有没有更好的方法来解决我的基本问题?

更新:

这是我的实际代码:

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] &lt;&lt; y.to_s

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

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

简而言之,我在三个不同的 API 调用中获取 user listuser policygroup policy,并努力将这三个整合到一个地方,以便我能从中理解。

【问题讨论】:

  • 这完全取决于数据源的结构。你能把它们也展示一下吗?
  • @BroiSatse,请查找更新。谢谢。

标签: perl ruby ruby arrays hash


【解决方案1】:

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

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

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

【讨论】:

  • 是的,我想不出除了哈希/数组之外的任何其他方法,因为这在 perl 中相当简单,而且我已经做了很多年了。我知道 Ruby 人不像 perl 人那样使用嵌套哈希/数组。只是我不知道在 ruby​​ 中实现相同目标的更好方法是什么。
  • 你能给我指出一些有助于我理解如何使用类来实现这一点的文档吗? +1。
  • 我创建了一个要点,希望能说明我在重构中的思考过程。我只在要点上走了这么远。您可以根据需要从中获取:gist.github.com/phluid61/8933665
  • 感谢您编写示例代码来解释不同的方法。阅读您的要点后,我当然知道更多红宝石。谢谢。是的,你提到的其他两种方法也有效。
【解决方案2】:

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

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 ]

【讨论】:

  • 我正在尝试使您的代码正常工作,因为它抱怨不存在任何方法并且还纠正了一些语法错误。同时,你能解释一下它在做什么吗?
【解决方案3】:

你如何将你的代码拆分成更容易理解的东西,直到它对你来说变得容易?

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"]}}

【讨论】:

  • 感谢您提供不同的方法。它完美地工作。但是,我将接受@Matty 的回答(他在gist 中提供),因为它是按时间顺序排列的。为您的时间和精力 +1。
  • @slayedbylucifer 哈哈,当然,没有问题 :-) 感谢您的体贴,在 SO 上很少见到!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-19
  • 2021-04-15
  • 1970-01-01
  • 2022-12-01
相关资源
最近更新 更多