按键数组的顺序对Ruby哈希进行排序

时间:2022-08-20 15:58:12

I have a hash:

我有一个散列:

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

How do I sort sample using the order of keys in sort_order:

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

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

Expected result:

预期结果:

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

All I can come up with is

我能想到的就是

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

There's got to be a better way. Hints?

一定有更好的办法。提示?

Keys without values should not be present, i.e. number of keys remain the same, which isn't the case with Sort Hash Keys based on order of same keys in array

没有值的键不应该存在,即键的数量保持不变,这不是基于数组中相同键的顺序排序散列键的情况。

4 个解决方案

#1


4  

A functional approach using the intersection of keys:

使用键的交集的功能方法:

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

As @Stefan noted, the abstraction Hash#slice from ActiveSupport's pretty much does the job:

正如@Stefan指出的,ActiveSupport的抽象化散列#切片几乎完成了任务:

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

#2


3  

Please, see my 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


3  

The code below does this. Note that I used has_key? because you want the output hash to contain all the keys in the input hash, even if their values are nil.

下面的代码可以做到这一点。注意我使用了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}

A simplification is to use each_with_object:

简化方法是使用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}

I like @tokland's idea of array intersection (&) better because it elmiinates the need for an if condition:

我喜欢@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}

#4


0  

Here is one more way this can be done:

还有一种方法可以做到:

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

Explanation:

解释:

First we create a hash that contains only desired keys in the right order.

首先,我们创建一个散列,该散列以正确的顺序只包含所需的键。

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

And then, we merge this hash with sample to get the values from sample.

然后,我们将散列与样本进行合并,从样本中获取值。

#1


4  

A functional approach using the intersection of keys:

使用键的交集的功能方法:

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

As @Stefan noted, the abstraction Hash#slice from ActiveSupport's pretty much does the job:

正如@Stefan指出的,ActiveSupport的抽象化散列#切片几乎完成了任务:

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

#2


3  

Please, see my 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


3  

The code below does this. Note that I used has_key? because you want the output hash to contain all the keys in the input hash, even if their values are nil.

下面的代码可以做到这一点。注意我使用了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}

A simplification is to use each_with_object:

简化方法是使用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}

I like @tokland's idea of array intersection (&) better because it elmiinates the need for an if condition:

我喜欢@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}

#4


0  

Here is one more way this can be done:

还有一种方法可以做到:

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

Explanation:

解释:

First we create a hash that contains only desired keys in the right order.

首先,我们创建一个散列,该散列以正确的顺序只包含所需的键。

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

And then, we merge this hash with sample to get the values from sample.

然后,我们将散列与样本进行合并,从样本中获取值。