将数组拆分为散列

Splitting up an array into a hash

我有一个大约有860项的数组,我想把它变成一个散列,数组结构是(Key1, value 1, value2, value 3, Key2, value 1, value 2, value 3。 ..........等等)除了在现实生活中它看起来像(彼得,150、39、345,约翰,123、450、402,玛丽,145、345、506...... ……)。原来这些是我调换在一起的四个数组,所以我可以从 4 个独立的数组开始达到相同的最终目标。

我要

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

我觉得应该有一个很好的巧妙方法来做到这一点,但它让我望而却步,可能是因为我了解得不够 ruby。

如果您知道数据总是以 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]}

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

另一种方式:

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]}
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 made its debut in Ruby v2.3. One could alternatively use 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]

Original these are four arrays which I have transposed together, so I could reach the same end goal by starting from 4 independent arrays.

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

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

您可以通过 zip:

组合 "value" 个数组
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 returns结果一样

试试这个

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