2014-11-03 143 views
0

我有許多包含相同鍵的哈希,但是彼此的順序都不一致。我需要重新排序每一個以使它們適合正確的順序:使哈希鍵與哈希常數的順序匹配

correct_order = { 
    :cat => "cat", 
    :dog => "dog", 
    :bear => "bear", 
    :zebra => "zebra", 
    :monkey => "monkey" 
} 

hash1 = { 
    :bear => "bear", 
    :cat => "cat" 
} 

hash2 = { 
    :cat => "cat", 
    :monkey => "monkey", 
    :zebra => "zebra", 
    :bear => "bear" 
} 

hash3 = { 
    :dog => "dog", 
    :monkey => "monkey", 
    :cat => "cat" 
} 

我怎麼會去比較HASH1,HASH2和hash3的關鍵爲了使每個鍵匹配其在correct_order散的地方嗎? hash2將變爲:

hash2 { 
    :cat => "cat", 
    :bear => "bear", 
    :zebra => "zebra", 
    :monkey => "monkey" 
} 

請注意,每個新的散列不一定具有所有的鍵。每個哈希將具有變化的大小和變化的順序。

謝謝

回答

1

對於散列元素的順序有一些需要說明的內容,但在向您展示如何執行您想要的操作之後,我會解決該問題。這假定您使用的是Ruby 1.9+,其中維護了密鑰插入的順序。

代碼

def reorder(hash, order) 
    keys = order & hash.keys 
    Hash[keys.zip(hash.values_at(*keys))] 
end 

例子

order = correct_order.keys 
    #=> [:cat, :dog, :bear, :zebra, :monkey] 

reorder(hash1, order) 
    #=> {:cat=>"cat", :bear=>"bear"} 
reorder(hash2, order) 
    #=> {:cat=>"cat", :bear=>"bear", :zebra=>"zebra", :monkey=>"monkey"} 
reorder(hash3, order) 
    #=> {:cat=>"cat", :dog=>"dog", :monkey=>"monkey"} 

說明

讓我們來看看代碼是如何處理與hash1

hash = hash1 
    #=> {:bear=>"bear", :cat=>"cat"} 
order 
    #=> [:cat, :dog, :bear, :zebra, :monkey] 
keys = order & hash.keys 
    #=> [:cat, :dog, :bear, :zebra, :monkey] & [:bear, :cat] 
    #=> [:cat, :bear] 
arr = keys.zip(hash.values_at(*keys)) 
    #=> keys.zip({:bear=>"bear", :cat=>"cat"}.values_at(*[:cat, :bear])) 
    #=> keys.zip({:bear=>"bear", :cat=>"cat"}.values_at(:cat, :bear)) 
    #=> keys.zip(["cat", "bear"]) 
    #=> [[:cat, "cat"], [:bear, "bear"]] 
Hash[arr] 
    #=> {:cat=>"cat", :bear=>"bear"} 

在Ruby 1.9+可以改爲寫最後步驟爲:

arr.to_h 

注意,方法Array#&保留了第一陣列的順序。

哈希爲了

此前Ruby 1.9的,你可以不依賴鍵值對的順序(讓我們只說鍵)的哈希值。 1.9改變了。現在您可以確信,枚舉散列的鍵時,枚舉的順序將遵循將鍵添加到散列的順序。被警告說,這一變化並沒有被所有的Rubyists所接受。如果你已經將哈希視爲無序集合二十年了,這是一個巨大的變化。就我個人而言,我喜歡這種變化,並且發現它有很好的用途。

2

你不能「排序」一個散列。

The doc說:哈希按照相應的鍵被插入的順序枚舉它們的值。所以你將不得不創建一個新的散列。例如:

def sort_hash(ordered_keys, hash_to_sort) 
    new_hash= {} 
    ordered_keys.each do |key| 
    new_hash[key]= hash_to_sort[key] if hash_to_sort.has_key?(key) 
    end 
    new_hash 
end 

correct_order = { 
    :cat => "cat", 
    :dog => "dog", 
    :bear => "bear", 
    :zebra => "zebra", 
    :monkey => "monkey" 
} 

hash2 = { 
    :cat => "cat", 
    :monkey => "monkey", 
    :zebra => "zebra", 
    :bear => "bear" 
} 
puts sort_hash(correct_order.keys, hash2) 

請注意,函數返回一個新的散列。 hash2未被修改。