1

我有一个大约860项的数组,我想把它变成一个hash,数组结构是(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

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

4

5 回答 5

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]}
于 2017-04-08T05:04:45.223 回答
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]
于 2017-04-08T05:17:13.877 回答
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]}

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

于 2017-04-08T03:42:01.977 回答
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]]

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

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返回相同的结果。

于 2017-04-08T14:48:31.423 回答
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]}
于 2017-06-23T11:32:13.447 回答