按键数组中的顺序对Ruby Hash进行排序

时间:2016-05-24 05:53:42

标签: ruby hash

我有一个哈希:

sample = { bar: 200, foo: 100, baz: 100 }

如何使用sample中的键顺序对sort_order进行排序:

sort_order = [:foo, :bar, :baz, :qux, :quux]

预期结果:

sample #=> { foo: 100, bar: 200, baz: 100 }

我能想到的只是

new_hash = {}
sort_order.each{|k| new_hash[k] = sample[k] unless sample[k].nil? }
sample = new_hash

必须有更好的方法。提示?

不应存在没有值的键,即键的数量保持不变,而Sort Hash Keys based on order of same keys in array

的情况则不然。

4 个答案:

答案 0 :(得分:9)

使用键交叉的功能方法:

new_sample = (sort_order & sample.keys).map { |k| [k, sample[k]] }.to_h
#=> {:foo=>100, :bar=>200, :baz=>100}

正如@Stefan所说,ActiveSupport的抽象Hash#slice几乎完成了这项任务:

require 'active_support/core_ext/hash'
new_sample = sample.slice(*sort_order)
#=> {:foo=>100, :bar=>200, :baz=>100}

答案 1 :(得分:3)

以下代码执行此操作。请注意,我使用了has_key?,因为您希望输出哈希包含输入哈希中的所有键,即使它们的值为nil

#!/usr/bin/env ruby

def sorted_hash(input_hash, key_sort_order)
  new_hash = {}
  key_sort_order.each do |key|
    if input_hash.has_key?(key)
      new_hash[key] = input_hash[key]
    end
  end
  new_hash
end

sort_order = [:foo, :bar, :baz, :qux, :quux]
sample = { bar: 200, foo: 100, baz: 100 }

puts sorted_hash(sample, sort_order)
# Outputs: {:foo=>100, :bar=>200, :baz=>100}

简化是使用each_with_object

def sorted_hash_two(input_hash, key_sort_order)
  key_sort_order.each_with_object({}) do |key, result_hash|
    if input_hash.has_key?(key)
      result_hash[key] = input_hash[key]
    end
  end
end

puts sorted_hash_two(sample, sort_order)
# Outputs: {:foo=>100, :bar=>200, :baz=>100}

我更喜欢@ tokland关于数组交集(&)的想法,因为它消除了对if条件的需求:

def sorted_hash_ewo_intersection(input_hash, key_sort_order)
  (key_sort_order & input_hash.keys).each_with_object({}) do |key, result_hash|
    result_hash[key] = input_hash[key]
  end
end # produces: {:foo=>100, :bar=>200, :baz=>100}

答案 2 :(得分:3)

请参阅我的this answer

sort_order = [:foo, :bar, :baz, :qux, :quux, :corge, :grault,
              :garply, :waldo, :fred, :plugh, :xyzzy, :thud]
sample = { bar: 200, foo: 100, baz: 100 }

sample.sort_by {|k, _| sort_order.index(k)}.to_h
=> {:foo=>100, :bar=>200, :baz=>100}

答案 3 :(得分:1)

以下是另一种方法:

(sort_order & sample.keys).zip([nil]).to_h.merge(sample)
#=> {:foo=>100, :bar=>200, :baz=>100}

<强>解释

首先,我们创建一个只包含正确顺序所需键的哈希值。

(sort_order & sample.keys).zip([nil]).to_h
#=> {:foo=>nil, :bar=>nil, :baz=>nil}

然后,我们将此哈希值与sample合并,以获取sample中的值。