如何按键按字母顺序对 Ruby Hash 进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27384967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 06:38:48  来源:igfitidea点击:

How to sort a Ruby Hash alphabetically by keys

rubysorting

提问by Rilcon42

I am trying to sort a Hash alphabetically by key, but I can't seem to find a way to do it without creating my own Sorting class. I found the code below to sort by value if it's an integer and I am trying to modify it but not having any luck.

我正在尝试按字母顺序键对 Hash 进行排序,但如果不创建自己的 Sorting 类,我似乎无法找到一种方法。如果它是一个整数,我发现下面的代码按值排序,我正在尝试修改它但没有任何运气。

temp["ninjas"]=36
temp["pirates"]=12
temp["cheese"]=222
temp.sort_by { |key, val| key }

My goal is to order the Hash by key then output the values. I will have to do this multiple times with different hash orders but the same values.

我的目标是按键对 Hash 进行排序,然后输出值。我将不得不使用不同的哈希顺序但相同的值多次执行此操作。

回答by Neil Slater

Assuming you want the output to be a hash which will iterate through keys in sorted order, then you are nearly there. Hash#sort_byreturns an Arrayof Arrays, and the inner arrays are all two elements.

假设您希望输出是一个散列,它将按排序顺序遍历键,那么您就快到了。Hash#sort_by返回一个Arrayof Arrays,内部数组都是两个元素。

Ruby's Hashhas a constructor that can consume this output.

Ruby 的Hash构造函数可以使用此输出。

Try this:

尝试这个:

temp = Hash[ temp.sort_by { |key, val| key } ]

or more concisely

或者更简洁

temp = temp.sort_by { |key| key }.to_h

If your hash has mixed key types, this will not work (Ruby will not automatically sort between Strings and Symbols for instance) and you will get an error message like comparison of Symbol with String failed (ArgumentError). If so, you could alter the above to

如果您的散列具有混合键类型,这将不起作用(例如,Ruby 不会自动在Strings 和Symbols之间排序)并且您将收到一条错误消息,例如将 Symbol 与 String 进行比较失败 (ArgumentError)。如果是这样,您可以将上述更改为

temp = Hash[ temp.sort_by { |key, val| key.to_s } ] 

to work around the issue. However be warned that the keys will still retain their original types which could cause problems with assumptions in later code. Also, most built-in classes support a .to_smethod, so you may get unwanted results from that (such as unexpected sort order for numeric keys, or other unexpected types).

解决这个问题。但是请注意,键仍将保留其原始类型,这可能会导致以后代码中的假设出现问题。此外,大多数内置类都支持一种.to_s方法,因此您可能会从中获得不需要的结果(例如数字键的意外排序顺序或其他意外类型)。

You could, in addition, convert the keys to Stringswith something like this:

此外,您可以将密钥转换为Strings以下内容:

temp = Hash[ temp.map { |key, val| [key.to_s, val] }.sort ] 

. . . although this approach would lose information about the type of the original key making it impossible to refer back to the original data reliably.

. . . 尽管这种方法会丢失有关原始密钥类型的信息,从而无法可靠地回溯原始数据。

回答by sickp

sorted_by_key = Hash[original_hash.sort]

will create a new Hash by inserting the key/values of original_hashalphabetically by key. Ruby 2.x hashes remember their insertion order, so this new hash will appear sorted by key if you enumerate it or output it.

将通过original_hash按字母顺序插入键/值来创建一个新的哈希键。Ruby 2.x 散列会记住它们的插入顺序,因此如果您枚举或输出它,这个新散列将按键排序。

If you insert more elements in a non-alphabetical order, this won't hold of course.

如果您以非字母顺序插入更多元素,这当然不会成立。

Also, this assumes the original hash keys are all sortable/comparable.

此外,这假设原始哈希键都是可排序/可比较的。

回答by the Tin Man

Ruby's Hash remembers its insertion order now days, but earlier Rubies < v1.9 don't. But, don't bother sorting a hash as there is no advantage to doing so because basically a Hash is a random-access structure. That means the elements are all accessible at any time and it won't make a difference whether one is first or last, you can access it just the same.

Ruby 的 Hash 现在可以记住它的插入顺序,但早期的 Ruby < v1.9 不记得了。但是,不要费心对散列进行排序,因为这样做没有任何好处,因为基本上散列是一种随机访问结构。这意味着所有元素都可以随时访问,无论是第一个还是最后一个都没有区别,您可以完全相同地访问它。

That's unlike an Array which acts like a sequential/text file or a chain or a queue and you have to access it linearly by iterating over it, which, at that point, the order of the elements makes a big difference.

这与 Array 不同,它的作用类似于顺序/文本文件或链或队列,您必须通过迭代来线性访问它,在这一点上,元素的顺序会产生很大的不同。

So, with a Hash, get the keys, sort them, and either iterate over the list of keys or use values_atto retrieve all the values at once. For instance:

因此,使用 Hash,获取键,对它们进行排序,然后迭代键列表或用于values_at一次检索所有值。例如:

hash = {
    'z' => 9,
    'a' => 1
}

sorted_keys = hash.keys.sort # => ["a", "z"]
sorted_keys.each do |k|
  puts hash[k]
end
# >> 1
# >> 9

hash.values_at(*sorted_keys) # => [1, 9]

Some languages won't even let you sort the hash, and accessing it via a sorted list of keys is the only way to extract the elements in an order, so it's probably a good idea to not get in the habit of relying on order of the key/value pairs, and instead rely on the keys.

有些语言甚至不允许您对哈希进行排序,并且通过排序的键列表访问它是按顺序提取元素的唯一方法,因此不养成依赖顺序的习惯可能是个好主意键/值对,而不是依赖于键。

回答by Jake

You can create a new empty hash to hold the sorted hash data. Iterate through the returned array and load the data into the new hash to hold the sorted hash data.

您可以创建一个新的空哈希来保存排序后的哈希数据。遍历返回的数组并将数据加载到新的散列中以保存排序后的散列数据。

temp = {}
temp["ninjas"]=36
temp["pirates"]=12
temp["cheese"]=222 
temp = temp.sort_by { |key, val| key }

temp_sorted = {}
temp.each { |sub_arr| temp_sorted[sub_arr[0]] = sub_arr[1] } 
temp = temp_sorted

temp now equals {"cheese"=>222, "ninjas"=>36, "pirates"=>12}

temp 现在等于 {"cheese"=>222, "ninjas"=>36, "pirates"=>12}

回答by Paul van Leeuwen

In addition to Neil Slater's answer, which uses the Hash#sort_bymethod (which is nice and concise when outputting comparable values in the block)...

除了Neil Slater's answer,它使用了该Hash#sort_by方法(在块中输出可比较的值时它非常简洁)......

irb(main):001:0> h = { a: 0, b: 5, c: 3, d: 2, e: 3, f:1 }
=> {:a=>0, :b=>5, :c=>3, :d=>2, :e=>3, :f=>1}
irb(main):002:0> h.sort_by { |pair| pair[1] }.to_h
=> {:a=>0, :f=>1, :d=>2, :c=>3, :e=>3, :b=>5}

...or the reverse variant...

...或相反的变体...

irb(main):003:0> h.sort_by { |pair| pair[1] }.reverse.to_h
=> {:b=>5, :e=>3, :c=>3, :d=>2, :f=>1, :a=>0}

...there is also the option to use the Array#sortmethod which allows you to define your own comparison rules (e.g. this sorts by value ascending, but then by key descending on equal values):

...还可以选择使用Array#sort允许您定义自己的比较规则的方法(例如,按值升序排序,然后按键降序对相等值排序):

irb(main):004:0> h.to_a.sort { |one, other| (one[1] == other[1]) ? other[0] <=> one[0] : one[1] <=> other[1] }.to_h
=> {:a=>0, :f=>1, :d=>2, :e=>3, :c=>3, :b=>5}

This last option is a bit less concise, but can be more flexible (e.g. custom logic to deal with a mixture of types).

最后一个选项不太简洁,但可以更灵活(例如处理混合类型的自定义逻辑)。