2014-04-10 129 views
1

我正在用運行時可用鍵構建散列表(因此事先不知道對象的大小)。我希望所有這些值都是ContestStanding類的新實例,但不是完全相同的實例。我已經與無限枚舉

h = Hash.new {|h,k| h[k] = ContestStanding.new} 
@my_keys.map {|k| h[k]} 
h #=> {1=>#<ContestStanding...>, 2=>#<ContestStanding...>, ...} 

實現這一點,我想知道如果有一種方法,我可以做到這一點使用枚舉或lambda表達式如下所示。注意:我已驗證這不起作用。這只是我的思考過程

Hash[@my_keys.zip(-> { ContestStanding.new })] 

這裏,問題是我的Lambda是不可枚舉的。 Ruby中有沒有類似無限生成器的東西?

編輯

我最初得到了真正由Enumerable#each_with_object方法絆倒。在塊參數中沒有看到kh的順序。以爲我瘋了!至於你的建議的執行情況,當我在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'}。對此有何想法?

+1

布拉德,你可以使用 'my_keys.each_with_object({}){| K,H | h [k] = ContestStanding.new}'其中'my_keys.each_with_object({})'是一個枚舉器。要使用'zip':'Hash [my_keys.zip(Array.new(my_keys.size,Hash.new {| h,k | h [k] = ContestStanding.new}))]'。這是你尋找的那種東西嗎? –

+1

爲了記錄,@ CarySwoveland的方法是我會使用的方法,我對你如何解決問題印象更深刻,我從來沒有想過(有點驚訝它的作品)!另一種方法肯定比較習慣,不太混亂。 –

+0

@CarySwoveland查看我對幾個問題的編輯 –

回答

1

Brad,

這裏有兩種方法可以產生散列。我將使用以下作爲一個例子:

class ContestStanding 
    def checkit 
    puts "hi" 
    end 
end 

my_keys = [1,2,3] 

使用Enumerable#each_with_object

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 

被類似地產生的散列值的其它元件。

使用Array.zip

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>} 
+0

Cary,很好的解釋!我在推理完block參數fiasco之後,通過IRB中的Enumerator#each_with_object'進行了推理。我從來沒有聽說過。太棒了!我在使用Enumerator的數組之後的思考過程是我希望它在內存中可能更小。說'my_keys'有1000個元素。我不會一次在內存中實例化1000個ContestStandings,然後立即將它們複製到新的數據結構中。我會在適當的地方創造它們一次。那有意義嗎? –

+0

'my_keys.zip'不是一個枚舉器,因此它不能鏈接到您的枚舉器來創建一個枚舉器。這意味着'zip'在它的參數完全構建之前不會做它的事情,就像它的參數是一個數組一樣。無論如何,'Hash'需要一個完整的元組數組來創建哈希。這是'each_with_object'方法的一個優點:不需要臨時數組。順便說一句,你可以使用'reduce'(又名'inject'),這是人們在'each_with_object'變得可用之前做的事情(我相信在v1.9中):'my_keys.reduce({}){| h ,K | h [k] = ContestStanding.new; h}'。 –

+0

哦!謝謝你的解釋。如果我能再問你一個問題,你會去哪裏?或者你會如何評估函數調用的性能?爲了監測效率?只是這樣我才能儘量避免在未來持續發佈類似這樣的問題 –

2

當我通過Enumerator文檔和a similar SO question挖,我玩弄了建立一個自定義枚舉。我在Enum塊中尋找嵌套的無限循環。最終的代碼出來這

Hash[@my_keys.zip(Enumerator.new {|y| loop { y << ContestStanding.new}})] 

這是相當吻我想要的東西!