你的代码有两个问题。第一个问题是当
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
h[2].object_id
h[4].object_id
啊哈,所有三个值都是同一个对象! 当
h
没有键
k
时,
new
的参数
[]
由
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时
h[k]
返回的值)。
或者
arr.each_with_index.with_object({}) { |(a,i),h| (h[a.size] ||= []) << i }
#=> {3=>[0], 2=>[1, 3], 4=>[2]}
这两者实际上是以下内容:
h = {}
arr.each_with_index do |a,i|
sz = a.size
h[sz] = [] unless h.key?(sz)
h[a.size] << i
end
h
另一种方法是使用
Enumerable#group_by,按数组大小进行分组,然后获取每个内部数组的索引。
h = arr.each_with_index.group_by { |a,i| a.size }
h.each_key { |k| h[k] = h[k].map(&:last) }
1表达式h[2] = h[2] << 1
使用方法Hash#[]=和Hash#[],这就是为什么在等号左侧的h[2]
不返回默认值。该表达式可以改写为h[2] ||= [] << 1
。
arr.with_object
,但失败了。 - ybakos#with_object
,避免了我在答案中使用的代码味道,需要在块外声明哈希。再次感谢您,Cary。能够从像您这样的大师那里学习是一种特权。 - Ed de Almeidawith_object
只能用于 Enumerator 对象。或者你可以说 Array 类没有定义with_object
方法。 - Sagar Pandyawith_object
是用于Enumerator
的,但是有Array#each_with_object
(和Enumerable#each_with_object
)。同样的,with_index
与each_with_index
也是如此。 - mu is too short