给出Ruby中的二维数组:
[ [1, 1, 1],
[1, 1],
[1, 1, 1, 1],
[1, 1]
]
我想创建一个Hash,其中键是每个内部数组的计数,值是原始数组的索引数组,其内部数组大小具有特定计数。产生的哈希将是:
{ 2 => [1, 3], 3 => [0], 4 => [2] }
如何在Ruby中简洁地表达这个功能?我正在尝试类似于Hash.new([]).tap { |h| array.each_with_index { |a, i| h[a.length] << i } }
的东西,但生成的哈希是空的。
答案 0 :(得分:5)
您的代码存在两个问题。第一个是当h
为空并且你写h[2] << 1
时,由于h
没有密钥2
,h[2]
会返回默认值,所以此表达式变为[] << 1 #=> [1]
,但[1]
未附加到哈希,因此不会添加任何键和值。
您需要撰写h[2] = h[2] << 1
1 。如果这样做,您的代码将返回h #=> {3=>[0, 1, 2, 3], 2=>[0, 1, 2, 3], 4=>[0, 1, 2, 3]}
。不幸的是,这仍然是不正确的,这使我们遇到了代码的第二个问题:您没有正确定义新创建的哈希默认值。
首先请注意
h[3].object_id
#=> 70113420279440
h[2].object_id
#=> 70113420279440
h[4].object_id
#=> 70113420279440
啊哈,这三个值都是同一个对象!当new
没有密钥[]
时,h[k]
会返回h
个参数k
。问题是,为添加到散列的所有键k
返回相同的数组,因此您将为第一个新键添加一个空值数组的键值对,然后为下一个新密钥的相同数组添加第二个键值对,依此类推。请参阅下文,了解如何定义哈希值。
通过这两个更改,您的代码可以正常工作,但我建议您按如下方式编写。
arr = [ [1, 1, 1], [1, 1], [1, 1, 1, 1], [1, 1] ]
arr.each_with_index.with_object(Hash.new {|h,k| h[k]=[]}) { |(a,i),h|
h[a.size] << i }
#=> {3=>[0], 2=>[1, 3], 4=>[2]}
使用Hash::new形式使用块来计算哈希的默认值(即哈希值h[k]
返回的值{ {1}}没有密钥h
),
或
k
这两者实际上都是如下:
arr.each_with_index.with_object({}) { |(a,i),h| (h[a.size] ||= []) << i }
#=> {3=>[0], 2=>[1, 3], 4=>[2]}
另一种方法是在为每个内部数组获取索引后,使用Enumerable#group_by对数组大小进行分组。
h = {}
arr.each_with_index do |a,i|
sz = a.size
h[sz] = [] unless h.key?(sz)
h[a.size] << i
end
h #=> {3=>[0], 2=>[1, 3], 4=>[2]}
1表达式h = arr.each_with_index.group_by { |a,i| a.size }
#=> {3=>[[[1, 1, 1], 0]],
# 2=>[[[1, 1], 1], [[1, 1], 3]],
# 4=>[[[1, 1, 1, 1], 2]]}
h.each_key { |k| h[k] = h[k].map(&:last) }
#=> {3=>[0], 2=>[1, 3], 4=>[2]}
使用方法Hash#[]=和Hash#[],这就是h[2] = h[2] << 1
左侧的h[2]
未返回的原因默认值。或者可以将此表达式写为=
。
答案 1 :(得分:3)
arry = [ [1, 1, 1],
[1, 1],
[1, 1, 1, 1],
[1, 1]
]
h = {}
arry.each_with_index do |el,i|
c = el.count
h.has_key?(c) ? h[c] << i : h[c] = [i]
end
p h
这会给你
{3=>[0], 2=>[1, 3], 4=>[2]}