【问题标题】:Generate a ruby two-dimensional array from ruby hashes从 ruby​​ 哈希生成一个 ruby​​ 二维数组
【发布时间】:2014-12-21 12:13:42
【问题描述】:

我有这样的红宝石散列(大约 20 个键/值除外):

{
  fake: "bar",
  test: "me",
  other: "here"
}

{
  fake: "object",
  test: "foo",
  other: "okay"
}

我需要从这些哈希中创建一个二维数组,如下所示:

[
  ["fake", "bar", "object"],
  ["test", "me", "foo"]
]

我考虑为每个键创建一个数组并循环遍历对象以推送它们的值:

fake_array = ["fake"]
items.each do |i|
  fake_array << i[:fake]
end

这意味着为每个数组创建一个数组(同样,大约 20 个),并将属性推送到它们各自的数组。这似乎很愚蠢 - 我认为有一种更清洁的方法可以做到这一点。帮忙?

【问题讨论】:

    标签: ruby arrays


    【解决方案1】:

    如果arr 是您的哈希数组,我建议:

    代码

    def combine(arr)
      arr.each_with_object({}) { |g,h|
        g.each { |k,v| (h[k] ||=[]) << v } }.map { |k,v| [k,*v] }
    end
    

    也可以写成:

    def combine(arr)
      arr.each_with_object(Hash.new {|h,k| h[k]=[]}) { |g,h|
        g.each { |k,v| h[k] << v } }.map { |k,v| [k,*v] } 
    end
    

    示例

    arr = [
      {
        fake: "bar",
        test: "me",
        other: "here"
      },
      {
        fake: "object",
        test: "foo",
        other: "okay"
      }
    ]
    
    h = combine(arr)
      #=> [[:fake, "bar", "object"], [:test, "me", "foo"],
      #    [:other, "here", "okay"]]
    

    说明

    g.each { |k,v| (h[k] ||=[]) << v } }
    

    arr 中每个散列g 的键值对添加到初始为空的散列h。对于k,v 中的每一个键值对,如果h 具有键k,则h 中的该键的值将是一个数组,因此我们执行:

    (h[k] ||= []) << v
      #=> (h[k] = h[k] || []) << v
      #=> (h[k] = h[k]) << v
      #=> h[k] << v
    

    但是,如果 h 没有那个密钥,h[k] =&gt; nil,那么:

    (h[k] ||= []) << v
      #=> (h[k] = nil || []) << v
      #=> (h[k] = []) << v
      #=> h[k]  = [v]
    

    我们首先创建哈希:

    hash = arr.each_with_object(Hash.new {|h,k| h[k]=[]}) { |g,h|
      g.each { |k,v| h[k] << v } }
      #=> {:fake=>["bar", "object"], :test=>["me", "foo"],
      #    :other=>["here", "okay"]}
    

    然后将其转换为所需的数组:

    hash.map { |k,v| [k,*v] }
      #=> [[:fake, "bar", "object"], [:test, "me", "foo"], [:other, "here", "okay"]]
    

    替代方案

    这是另一种方式:

    def combine(arr)
      arr.each_with_object({}) { |g,h|
        h.update(g.merge(g) { |*_,v| [v] }) { |_,ov,nv| ov + nv } }
         .map { |k,v| [k,*v] }
    end
    

    这使用Hash#update(又名merge!)的形式,它使用一个块来解析存在于被合并的两个哈希中的键的值。

    在合并之前,每个哈希都被转换为一个哈希,其键相同,其值是这些值的数组。例如,

    g = {
      fake: "bar",
      test: "me",
      other: "here"
    }
    

    转换为:

    g.merge(g) { |*_,v| [v] }
      #=> {
      #     fake:  ["bar"],
      #     test:  ["me"],
      #     other: ["here"]
      #   }
    

    这为我们提供了与第一种方法产生的相同的哈希值,并使用相同的代码将其转换为数组。

    【讨论】:

      【解决方案2】:
      h1 = {
        fake: "bar",
        test: "me",
        other: "here"
      }
      
      h2 = {
        fake: "object",
        test: "foo",
        other: "okay"
      }
      
      arr = []
      h1.merge(h2){|k,o,n| [k.to_s,o,n]}.each_value{ |v| arr << v}
      
      (main):0 > arr
      => [["fake", "bar", "object"], ["test", "me", "foo"], ["other", "here", "okay"]]
      

      【讨论】:

      • h1 中,如果将fake: "bar" 更改为real: "car",则会得到:arr #=&gt; ["car", ["test", "me", "foo"], ["other", "here", "okay"], "object"]
      【解决方案3】:

      试试这个:

      require 'pp'
      
      def hash_to_arr(arr_of_hashes)
        temp_hash = {}
      
        arr_of_hashes.each do |hash|
          hash.each do |k,v|
            ks = k.to_s
            if(temp_hash[ks])
              temp_hash[ks] << v 
            else
              temp_hash[ks] = [v]
            end
          end
        end
        result = []
        temp_hash.each do |k,v|
          result << [k, *v] 
        end
        result
      end
      
      pp hash_to_arr [
        {
          fake: "bar",
          test: "me",
          other: "here"
        },
        {
          fake: "object",
          test: "foo",
          other: "okay"
        }
      ]
       # => [["fake", "bar", "object"], ["test", "me", "foo"], ["other", "here", "okay"]]
      

      【讨论】:

        【解决方案4】:

        这是一个简洁的,我认为可以满足您的需求。给定哈希 X1, X2, ... Xn

        result = []
        x1.zip(x2, xn) { |arr| result << arr.flatten.uniq.map(&:to_s) }
        

        【讨论】:

          【解决方案5】:

          在 Ruby 1.9 或更高版本中,哈希是有序的。如果您预先订购/对齐您的两个哈希,您可以这样做:

          a = {:fake=>"bar", :test=>"me", :other=>"here"}
          b = {:fake=>"object", :test=>"foo", :other=>"okay"}
          
          a.keys.zip(a.values,b.values)
          

          => [[:fake, "bar", "object"], [:test, "me", "foo"], [:other, "here", "okay"]]

          【讨论】:

          • 这假定两个哈希具有相同的键。
          猜你喜欢
          • 2021-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-20
          • 1970-01-01
          • 2014-12-10
          相关资源
          最近更新 更多