我有一系列哈希:
a = [
{ :id => 10, :name => 'bush' },
{ :id => 2, :name => 'sugar' },
{ :id => 10, :name => 'mountain' },
{ :id => 10, :name => 'bug' },
{ :id => 8, :name => 'sugar' }
]
我想首先按数字上升的数字对数组进行排序,然后按名称按字母顺序降序,以便最终结果为:
a = [
{ :id => 2, :name => 'sugar' },
{ :id => 8, :name => 'sugar' },
{ :id => 10, :name => 'mountain' },
{ :id => 10, :name => 'bush' },
{ :id => 10, :name => 'bug' }
]
我如何实现这一目标?
答案 0 :(得分:4)
根据您对问题所做的修改,要进行传统排序,您可以使用
a.sort { |a, b| [a[:id], a[:name]] <=> [b[:id], b[:name]] }
=> [
{:id=>2, :name=>"sugar"},
{:id=>8, :name=>"sugar"},
{:id=>10, :name=>"bug"},
{:id=>10, :name=>"bush"},
{:id=>10, :name=>"mountain"}
]
您可以通过交换条件检查来切换排序顺序。
a.sort { |a, b| [a[:id], b[:name]] <=> [b[:id], a[:name]] }
=> [
{:id=>2, :name=>"sugar"},
{:id=>8, :name=>"sugar"},
{:id=>10, :name=>"mountain"},
{:id=>10, :name=>"bush"},
{:id=>10, :name=>"bug"}
]
答案 1 :(得分:1)
a.sort {| a,b | (a [:id]!= b [:id])? a [:id]&lt; =&gt; b [:id]:b [:name]&lt; =&gt; a [:name]}
>> a
=> [{:id=>10, :name=>"bush"}, {:id=>2, :name=>"sugar"}, {:id=>10, :name=>"mountain"}, {:id=>10, :name=>"bug"}, {:id=>8, :name=>"sugar"}]
>> a.sort {|a,b| (a[:id] != b[:id]) ? a[:id] <=> b[:id] : b[:name] <=> a[:name] }
=> [{:id=>2, :name=>"sugar"}, {:id=>8, :name=>"sugar"}, {:id=>10, :name=>"mountain"}, {:id=>10, :name=>"bush"}, {:id=>10, :name=>"bug"}]
>>
答案 2 :(得分:1)
我认为@DanReedy的答案非常清晰,但如果你将它应用于大型列表可能会产生性能问题,因为它会产生很多(O(N logN)的小型中间数组和重复的哈希查找。{{一旦在O(N logN)比较中重复使用O(N),可以帮助制作排序键。为了完成二级密钥的降序排序,我们需要一种方法来反转比较方法的排序。
sort_by
答案 3 :(得分:1)
只是为了好玩,这是一种多年来一直存在的模式:
class SortByInverter < Struct.new(:value)
def <=>(other)
other.value <=> value
end
end
class Object
def desc
SortByInverter.new(self)
end
end
现在让我们使用它:
hs.sort_by { |h| [h[:id], h[:name].desc] }
当然我们可以直接使用容器类(更详细,但没有Object
的可怕扩展名):
hs.sort_by { |h| [h[:id], SortByInverter.new(h[:name])] }
答案 4 :(得分:0)
你可以尝试类似的东西
a.sort do |a1, a2|
comparison = a1[:id] <=> a2[:id]
(comparison != 0) ? comparison : a1[:name] <=> a2[:name]
end