1

我有一个哈希数组:

a = [
  { :id => 10, :name => 'bush' },
  { :id => 2, :name => 'sugar' },
  { :id => 10, :name => 'mountain' },
  { :id => 10, :name => 'bug' },
  { :id => 8, :name => 'sugar' }
]

我想先按 id 升序对数组进行排序,然后按名称按字母降序对数组进行排序,这样最终结果将是:

a = [
  { :id => 2, :name => 'sugar' },
  { :id => 8, :name => 'sugar' },
  { :id => 10, :name => 'mountain' },
  { :id => 10, :name => 'bush' },
  { :id => 10, :name => 'bug' }
]

我如何实现这一目标?

4

5 回答 5

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"}
]
于 2013-03-15T16:13:21.537 回答
1

a.sort {|a,b| (a[:id] != b[:id]) ?a[:id] <=> b[:id] : b[:name] <=> 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"}]
>>
于 2013-03-15T16:11:42.987 回答
1

我认为@DanReedy 的答案非常清楚,但是如果您将其应用于大型列表,则可能会出现性能问题,因为制作了很多( O(N logN) 的小型中间数组和重复的哈希查找。 sort_by可以通过使排序键一次 O(N) 以便在 O(N logN) 比较中重复使用。为了完成辅助键的降序,我们需要一种方法来反转比较方法的顺序。

module DescendingComparable
  def <=>(other)
    - super
  end
end

pry(main)> a.sort_by {|e| [ e[:id], e[:name].dup.extend(DescendingComparable) ] }
=> [{:id=>2, :name=>"sugar"},
 {:id=>8, :name=>"sugar"},
 {:id=>10, :name=>"mountain"},
 {:id=>10, :name=>"bush"},
 {:id=>10, :name=>"bug"}]
于 2013-03-15T19:09:09.947 回答
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])] }
于 2013-03-15T19:55:54.847 回答
0

你可以尝试类似的东西

a.sort do |a1, a2|
  comparison = a1[:id] <=> a2[:id]
  (comparison != 0) ? comparison : a1[:name] <=> a2[:name]
end
于 2013-03-15T16:12:21.520 回答