将数组拆分为哈希

时间:2017-04-08 03:17:41

标签: arrays ruby ruby-hash

我有一个大约860项的数组,我想把它变成一个哈希,数组结构是(Key1,value 1,value2,value 3,Key2,value 1,value 2,value 3 ... ........等等除了在现实生活中它看起来像(Peter,150,39,345,John,123,450,402,Mary,145,345,506 ........ ....)。原来这些是我已经转换到的四个阵列,所以我可以通过从4个独立阵列开始达​​到相同的最终目标。

我想

Hash {Peter=> [150, 39, 345], John=>[123,450,402], Mary => [145,345,506] etc etc

我觉得应该有一个很好的方法来做到这一点,但它让我望而却步,可能是因为我不知道足够的红宝石。

5 个答案:

答案 0 :(得分:4)

还有一种方法:

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]

Hash[*l.each_slice(4).flat_map { |a, *b| [a, b] }]
#=> {"Peter"=>[150, 39, 345], 
#    "John" =>[123, 450, 402], 
#    "Mary" =>[145, 345, 506]}

如果您已有阵列,解决方案将更加简单:

arrays = [array_1, array_2, array_3]
Hash[*arrays.flat_map {|a, *b| [a, b]} ]
#=> {"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]}

答案 1 :(得分:3)

arr = ['Peter', 150, 39, 345, 'John', 123, 450, 'Mary', 145, 345, 506, 222]

arr.slice_before {|a| String === a }.
    each_with_object({}) {|(f,*rest), h| h[f] = rest}
  #=> {"Peter"=>[150, 39, 345], "John"=>[123, 450], "Mary"=>[145, 345, 506, 222]} 

Enumerable#slice_before在Ruby v2.3中首次亮相。也可以使用Enumerable#slice_when,这是v2.2中的新内容。

以下是使用早期版本Ruby的几种方法。

arr.chunk { |e| String === e }.
    each_slice(2).
    with_object({}) { |((_,(k)),(_,v)), h| h[k] = v }

a = []
enum = arr.to_enum
loop do
  o = enum.next
  (String === o) ? a << [o,[]] : a.last.last << o
end
Hash[a]

答案 2 :(得分:1)

如果您知道数据总是以4组为准:

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]
h = {}
l.each_slice(4).each do |chunk|
    h[chunk[0]] = chunk[1..chunk.length]
end

或者,如果你知道键总是字符串:

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]
h = {}
current_key = ""
l.each do |item|
    if item.is_a? String
        current_key = item
        h[item] = []
    else 
        h[current_key] << item 
    end 
end

基本上,你需要弄清楚如何恰当地切割数组然后循环。

此外,如果您已将它们作为单独的阵列获得,您可以轻松地:

array_1 = ['Peter', 150, 39, 345]
array_2 = ['John', 123, 450, 402]
array_3 = ['Mary', 145, 345, 506]
h = {}    

[array_1,array_2, array_3].each do |a|
    h[a[0]] = a[1:a.length]
end

# One line version:
[array_1,array_2, array_3].map{|a| h[a[0]] = a[1..a.length]}

我认为这是最干净的方法。

答案 3 :(得分:1)

  

原来这些是我已经转换过的四个阵列,因此我可以从4个独立阵列开始达​​到相同的最终目标。

我假设你有这样的事情开头:

a = ["Peter", "John", "Mary"]
b = [150, 123, 145]
c = [39, 450, 345]
d = [345, 402, 506]

您可以通过zip组合“值”数组:

values = b.zip(c, d)
#=> [[150, 39, 345], [123, 450, 402], [145, 345, 506]]

通过另一个zip添加“key”数组:

a.zip(values)
#=> [["Peter", [150, 39, 345]], ["John", [123, 450, 402]], ["Mary", [145, 345, 506]]]

这已经是正确的结构,所以我们可以调用to_h

a.zip(values).to_h
#=> {"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]}

当然你不需要中间变量,a.zip(b.zip(c, d)).to_h会返回相同的结果。

答案 4 :(得分:0)

试试这个

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]

l.each_slice(4).to_a.inject({}){|acc, temp| acc[temp.first]=temp.last(3); acc}

#=>{"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]}