从红宝石哈希生成红宝石二维阵列

时间:2014-12-19 23:46:13

标签: ruby arrays

我有像这样的红宝石哈希(大约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个),并将属性推送到各自的数组。这看起来很愚蠢 - 我认为有一种更清洁的方法可以做到这一点。帮助

5 个答案:

答案 0 :(得分:2)

如果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 } }

g中每个哈希值arr的键值对添加到最初为空的哈希值h。对于每个键值对k,v,如果h具有键k,则h中该键的值将为数组,因此我们执行:< / p>

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

但是,如果h没有该密钥h[k] => 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"]
  #   }

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

试试这个:

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

答案 3 :(得分:0)

这是一个简洁的,我认为你做的是你所追求的。给定哈希值X1,X2,... Xn

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

答案 4 :(得分:0)

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

a = {:fake=>"bar", :test=>"me", :other=>"here"}
b = {:fake=>"object", :test=>"foo", :other=>"okay"}

a.keys.zip(a.values,b.values)

=&GT; [[:fake,&#34; bar&#34;,&#34; object&#34;],[:test,&#34; me&#34;,&#34; foo&#34;],[:other ,&#34;这里&#34;,&#34;好的&#34;]]