使哈希键与哈希常量的顺序匹配

时间:2014-11-03 23:28:41

标签: ruby sorting hash

我有许多哈希包含相同的键,但彼此之间都是乱序的。我需要重新排序每一个以使它们符合正确的顺序:

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"
}

请注意,每个新哈希都不一定拥有所有密钥。每个哈希的大小和变化顺序都不同。

谢谢

2 个答案:

答案 0 :(得分: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未被修改。

答案 1 :(得分: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变了。现在您可以确信,当您枚举散列的键时,枚举的顺序将遵循将键添加到散列的顺序。请注意,所有Rubyist都没有接受这种改变。如果你二十年来一直认为哈希是无序的集合,这是一个很大的变化。就个人而言,我喜欢这种变化并且已经找到了很好的用途。