ruby - 按值对哈希进行排序时如何保留键的字母顺序

标签 ruby sorting hash key-value alphabetical

这里是初学者。我的第一个问题。对我放轻松。

给定以下哈希:

pets_ages = {"Eric" => 6, "Harry" => 3, "Georgie" => 12, "Bogart" => 4, "Poly" => 4,
        "Annie" => 1, "Dot" => 3}

并运行以下方法:

pets_ages.sort {|x, y| x[1] <=> y[1]}.to_h

返回以下内容:

{
      "Annie" => 1,
        "Dot" => 3,
      "Harry" => 3,
       "Poly" => 4,
     "Bogart" => 4,
       "Eric" => 6,
    "Georgie" => 12
}

您会注意到哈希按照预期很好地按值排序。我想更改的是键的顺序,以便在平局的情况下它们保持字母顺序。请注意,“Dot”和“Harry”在这方面是正确的,但出于某种原因,“Poly”和“Bogart”不是。我的理论是,在平局的情况下,它会自动按长度对键进行排序,而不是按字母顺序排序。我该如何改变它?

最佳答案

在许多语言中,Hashes/Dicts 是无序的,因为它们是如何在幕后实现的。 Ruby 1.9+ 足以保证排序。

您可以一次完成此操作 - Ruby 允许您按任意标准进行排序。

# Given
pets_ages = {"Eric" => 6, "Harry" => 3, "Georgie" => 12, "Bogart" => 4, "Poly" => 4, "Annie" => 1, "Dot" => 3}

# Sort pets by the critera of "If names are equal, sort by name, else, sort by age"
pets_ages.sort {|(n1, a1), (n2, a2)| a1 == a2 ? n1 <=> n2 : a1 <=> a2 }.to_h

# => {"Annie"=>1, "Dot"=>3, "Harry"=>3, "Bogart"=>4, "Poly"=>4, "Eric"=>6, "Georgie"=>12}

Hash#sort 将返回 [k, v] 的数组对,但那些 k, v可以在一次通过中按您想要的任何标准对对进行排序。一旦我们有了排序的对,我们就把它转回一个哈希 Array#to_h (Ruby 2.1+),或者你可以使用 Hash[sorted_result]在早期版本中,正如 Beartech 指出的那样。

你可以在排序 block 中得到你想要的那么复杂;如果您熟悉 Javascript 排序,那么 Ruby 在这里的工作原理实际上是一样的。 <=>方法根据对象相互比较的方式返回 -1、0 或 1。 #sort 只期望这些返回值之一,它告诉它两个给定值如何相互关联。您甚至不必使用 <=>如果您不想,则完全不这样做 - 这样的事情相当于更紧凑的形式:

pets_ages.sort do |a, b|
  if a[1] == b[1]
    if a[0] > b[0]
      1
    elsif a[0] < b[0]
      -1
    else
      0
    end
  else
    if a[1] > b[1]
      1
    elsif a[1] < b[1]
      -1
    end
  end
end

如您所见,只要您始终返回集合 (-1 0 1) 中的某些内容,您的排序函数就可以做任何您想做的事情,因此您可以随心所欲地组合它们。然而,由于 super 方便的 <=> 运算符,在 Ruby 中几乎不需要这样冗长的形式!

不过,正如 Stefan 指出的那样,这里有一个很大的快捷方式:Array#<=> 足以 compare each entry between the compared arrays .这意味着我们可以做类似的事情:

pets_ages.sort {|a, b| a.reverse <=> b.reverse }.to_h

这需要每个 [k, v] 对,将其反转为 [v, k],并使用 Array#<=> 进行比较。由于您需要对比较的每个 [k, v] 对执行相同的操作,因此您可以使用 #sort_by 进一步缩短它

pets_ages.sort_by {|k, v| [v, k] }.to_h

它所做的是对每个哈希条目,它把键和值传递给 block , block 的返回结果就是用来比较这个 [k, v] 对和其他条目的。由于将 [v, k] 与另一个 [v, k] 对进行比较会得到我们想要的结果,我们只需返回一个由 [v, k] 组成的数组,其中 sort_by 收集并排序原始 [k, v] 对.

关于ruby - 按值对哈希进行排序时如何保留键的字母顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29402422/

相关文章:

python - 当详细信息肯定在数据库中时,验证电子邮件和散列密码总是返回 None

javascript - 如何自动验证优惠券并调整价格?

ruby-on-rails - 将 Rails 应用程序连接到 PGAdmin 4

ruby - 将 ruby​​ 哈希转换为数组的最佳方法是什么

php - 为什么 asort 与多维数组一起使用?

PHP 降序从 foreach 循环值存储的数组

ruby-on-rails - ruby rails : localhost:3000/my_pages_dont_show_up

java - 日期 ArrayList 的排序

ruby-on-rails - 如何在哈希栏中搜索单词

javascript - HTML5 视频如果哈希值等于值,则使用 Javascript 函数将音频设置为 1,否则将音频设置为 0