我在运行时使用可用的键构建哈希(因此事先不知道对象的大小)。我希望所有这些值都是类ContestStanding
的新实例,但不是完全相同的实例。我用
h = Hash.new {|h,k| h[k] = ContestStanding.new}
@my_keys.map {|k| h[k]}
h #=> {1=>#<ContestStanding...>, 2=>#<ContestStanding...>, ...}
我想知道我是否可以使用Enums或Lambdas这样做,如下所示。注意:我已经确认这不起作用。这只是我的思考过程
Hash[@my_keys.zip(-> { ContestStanding.new })]
在这里,问题是我的Lambda不可枚举。 Ruby中有无限生成器吗?
修改
我最初真的被Enumerable#each_with_object
方法绊倒了。在块参数中没有看到k
和h
的顺序。以为我疯了!至于你建议的实现,当我在IRB中运行时,这就是我得到的
my_keys = [1,2,3]
my_keys.each_with_object({}) {|k,h| h[k] = 'a'}
#=> {1=>"a", 2=>"a", 3=>"a"}
# The above is what I want to get out of the implementation
Hash[my_keys.zip(Array.new(my_keys.size, Hash.new {|h,k| h[k] = 'a'}))]
#=> {1=>{}, 2=>{}, 3=>{}}
我不是在寻找哈希哈希。这似乎是实现的回归。我想要回来{1=>'a', 2=>'a', 3=>'a'}
。有什么想法?
答案 0 :(得分:3)
当我挖掘Enumerator文档和a similar SO question时,我开始构建自定义枚举。我在Enum块中寻找嵌套的无限循环。最终的代码出现在这个
Hash[@my_keys.zip(Enumerator.new {|y| loop { y << ContestStanding.new}})]
这非常接近我想要的东西!
答案 1 :(得分:1)
布拉德,
以下是两种生成哈希的方法。我将使用以下作为示例:
class ContestStanding
def checkit
puts "hi"
end
end
my_keys = [1,2,3]
h = my_keys.each_with_object({}) { |k,h| h[k] = ContestStanding.new }
#=> {1=>#<ContestStanding:0x000001010efdd8>,
# 2=>#<ContestStanding:0x000001010efdb0>,
# 3=>#<ContestStanding:0x000001010efd88>}
h[1].checkit #=> "hi"
each_with_object
创建并清空由块参数h
引用的数组。传递给块的第一个值(并分配给块参数k
)是my_keys.first => 1
,所以
h[1] = ContestStanding.new
哈希的其他元素也是类似的。
Hash[my_keys.zip(Array.new(my_keys.size) {ContestStanding.new})]
#=> {1=>#<ContestStanding:0x0000010280f720>,
# 2=>#<ContestStanding:0x0000010280f6f8>,
# 3=>#<ContestStanding:0x0000010280f6d0>}
或者,对于Ruby v2.0 +
my_keys.zip(Array.new(my_keys.size) {ContestStanding.new}).to_h
#=> {1=>#<ContestStanding:0x0000010184bd48>,
# 2=>#<ContestStanding:0x0000010184bd20>,
# 3=>#<ContestStanding:0x0000010184bcf8>}
此处执行以下步骤:
a = Array.new(my_keys.size) {ContestStanding.new}
#=> [#<ContestStanding:0x0000010185b248>,
# #<ContestStanding:0x0000010185b220>,
# #<ContestStanding:0x0000010185b1f8>]
b = my_keys.zip(a)
#=> [[1, #<ContestStanding:0x0000010185b248>],
# [2, #<ContestStanding:0x0000010185b220>],
# [3, #<ContestStanding:0x0000010185b1f8>]]
b.to_h
#=> {1=>#<ContestStanding:0x0000010185b248>,
# 2=>#<ContestStanding:0x0000010185b220>,
# 3=>#<ContestStanding:0x0000010185b1f8>}
您的解决方案
我发现你的解决方案很有趣。这是解释其工作原理的一种方式:
enum = Enumerator.new { |y| loop { y << ContestStanding.new } }
#=> #<Enumerator: #<Enumerator::Generator:0x000001011a9530>:each>
a1 = my_keys.size.times.with_object([]) { |k,a| a << enum.next }
#=> [#<ContestStanding:0x000001018820a0>,
# #<ContestStanding:0x00000101882028>,
# #<ContestStanding:0x00000101881fb0>
a2 = my_keys.zip(a1)
#=> [[1, #<ContestStanding:0x000001018820a0>],
# [2, #<ContestStanding:0x00000101882028>],
# [3, #<ContestStanding:0x00000101881fb0>]]
Hash[a2]
#=> {1=>#<ContestStanding:0x000001018820a0>,
# 2=>#<ContestStanding:0x00000101882028>,
# 3=>#<ContestStanding:0x00000101881fb0>}