2010-06-21 46 views
0

嘿,伙计们,我有一个问题。我想转换数组。 [[1, [-1, 1]], [1, [20, 8]], [1, [30, 4]], [1, [40, 2]], [1, [41, 6]], [1, [70, 243]]]进入这种风格[1,[[-1,1],[20,8],[30,4]...]或哈希[1 => ...] 我该怎么办这个伎俩?谢谢 !红宝石阵列的问题!

回答

6

快译通方法:

array = [your array] 
dict = {} 
array.each{ |a| (dict[a[0]] ||= []) << a[1] } 

为了清晰Chuck的建议是要把这个:

array = [your array] 
dict = Hash.new {|h,k| h[k] = []} 
array.each{ |a| dict[a[0]] << a[1] } 

然后,您可以通过做从中得到的风格,你想数组:

new_arr = dict.select{|k,v| [k, v]} 

这会给你:

[[1, [[-1, 1], [20, 8], [30, 4], [40, 2], [41, 6], [70, 243]]]] 

注意额外的数组,因为如果你的数组是2开始的,你会在结尾有另一个数组。所以new_arr[0]会给你你最初寻找的阵列。

+3

你也可以很容易地派生出这样的数组。创建散列,然后执行'hash.map {| key,values | [key,values]}'。另外,通过将哈希创建为'Hash.new {[]}',您可以大大简化您的'each' - 然后在每次迭代中不需要对'|| = []'进行操作,因为不存在的键将返回一个空阵列。 – Chuck 2010-06-21 04:39:19

+0

'Hash.new {[]}'只适用于像'+ ='这样的赋值操作符,但是'''它不会。我相应地编辑了答案。 – 2010-06-22 00:57:23

0

你可以这样做:

array = [[1, [-1, 1]], [1, [20, 8]], [1, [30, 4]], 
     [1, [40, 2]], [1, [41, 6]], [1, [70, 243]]] 

# map into hashes that can be merged together 
hashes = array.map do |key,value| 
    { key => [value] } 
end 

# fold all hashes into one hash by merging the values by key 
merged_hash = hashes.inject({}) do |accu,value| 
    accu.merge!(value) {|_,o,n| o|n } 
end 

这可以写成一个不是那么容易的一行:

array.map{|k,v|{k=>[v]}}.inject({}){|a,v|a.merge!(v){|_,o,n|o|n}} 
#==> {1=>[[-1, 1], [20, 8], [30, 4], [40, 2], [41, 6], [70, 243]]} 
+0

这似乎比马特的解决方案更复杂,没有任何好处。你为什么喜欢这种做法? – Chuck 2010-06-21 05:30:15

+0

@Chuck它通过使用'inject'来解决问题,而不会污染局部变量名称空间。我更喜欢|| = []的'merge'方法。当然这是一个品味问题。但我认为Matt的解决方案也可以使用'inject'重写,从而防止用临时变量污染命名空间。 – hurikhan77 2010-06-21 07:45:46

2

如果你想把它当作一个Hash,它只是

h = Hash[ary.group_by(&:first).map {|k, v| [k, v.map(&:last)] }] 

如果你想要它作为Array,你只需将Hash转换为一个Array

a = *h 
+0

+1为一个非常优雅的解决方案,但我想提一下,group_by可能不适用于较旧的ruby API。 – hurikhan77 2010-06-21 11:58:40

+0

我相信'.group_by'是ruby 1.9,尽管可能有rails选项。 – 2010-06-21 13:49:13

+0

该代码在Ruby 1.8.7及更新版本中未修改运行。要在Ruby 1.8.6中使用它,你必须要求''Enumerable#group_by'和'Symbol#to_proc'的backports。 – Chuck 2010-06-22 00:04:33