按Ruby进行排序,一个降序,一个升序。

5
我在这个问题上进行了搜索,但没有找到答案,虽然有一个类似的问题,但那个回答在这种情况下不起作用,它对数字项进行排序。 类似的问题 - 没有解决 我正在尝试使用ruby的sort_by方法,按照其中一个项目升序排序,另一个项目降序排序。我能找到的只有其中之一。
以下是代码:
# Primary sort Last Name Descending, with ties broken by sorting Area of interest.
people = people.sort_by { |a| [ a.last_name, a.area_interest]}

希望您能提供任何指导。

样本数据:

输入

  • Russell,逻辑
  • Euler,图论
  • Galois,抽象代数
  • Gauss,数论
  • Turing,算法
  • Galois,逻辑

输出

  • Turing,算法
  • Russell,逻辑
  • Gauss,数论
  • Galois,抽象代数
  • Galois,逻辑
  • Euler,图论

3
Example input: "Hello, how are you?"Output: "你好,你怎么样?" - Arup Rakshit
请链接到类似的问题。 - Josh
1
我编辑了我的答案,给出了一个例子,可能更好地回答了你提出的问题,并展示了如何将表达式限制为排序元组,就像你的问题一样。 - Cary Swoveland
2个回答

5

这是一种直接的方法:

a = [ ['Russell', 'Logic'],           ['Euler', 'Graph Theory'],
      ['Galois', 'Abstract Algebra'], ['Gauss', 'Number Theory'],
      ['Turing', 'Algorithms'],       ['Galois', 'Logic'] ]

a.sort { |(name1,field1),(name2,field2)|
  (name1 == name2) ? field1 <=> field2 : name2 <=> name1 }
#=> [ ["Turing", "Algorithms"],   ["Russell", "Logic"],
#     ["Gauss", "Number Theory"], ["Galois", "Abstract Algebra"],
#     ["Galois", "Logic"],        ["Euler", "Graph Theory"] ]

对于多个字段,首先按照第一个字段降序排序,然后按照其他字段的顺序依次升序排序:

a = [ %w{a b c}, %w{b a d}, %w{a b d}, %w{b c a}, %w{a b c}, %w{b c b}]
  #=> [["a", "b", "c"], ["b", "a", "d"], ["a", "b", "d"],
  #    ["b", "c", "a"], ["a", "b", "c"], ["b", "c", "b"]] 

a.sort { |e,f| e.first == f.first ? e[1..-1] <=> f[1..-1] : f <=> e }
  #=> [["b", "a", "d"], ["b", "c", "a"], ["b", "c", "b"],
  #    ["a", "b", "c"], ["a", "b", "c"], ["a", "b", "d"]] 

太好了!我喜欢你的方法。+1。e[1..-1] <=> f[1..-1] 这部分是在做什么?你能解释一下吗? - Arup Rakshit
谢谢,@Arup。当两个数组具有相同的第一个元素(“Galois”)时,通过使用Array#<=>比较这些数组的其余部分来打破平局。 - Cary Swoveland
这也是一种好方法,@Cary,如果有另外两列该怎么使用呢?我仍在学习中,每一个细节都很有用。谢谢。 - diek
请查看我之前评论中的链接。文档中已经很好地解释了。如果对于任何一对数组,第一个 n (n > 0) 个元素(字符串)相等且第 n+1 个元素不相等,则使用第 n+1 个元素来比较这两个数组。(<=>,即升序)。 - Cary Swoveland
我错过了那个。我来自Python背景。虽然我真的很喜欢Ruby,文档也不错,但它还没有达到Python的水平。 - diek

4

创建一个自定义类,反转<=>的结果(包括Comparable)。

使用自定义类包装您想要按降序排序的对象。

示例:

class Descending
  include Comparable
  attr :obj

  def initialize(obj)
    @obj = obj
  end
  def <=>(other)
    return -(self.obj <=> other.obj)
  end
end

people = [
  {last_name: 'Russell', area_interest: 'Logic'},
  {last_name: 'Euler', area_interest: 'Graph Theory'},
  {last_name: 'Galois', area_interest: 'Abstract Algebra'},
  {last_name: 'Gauss', area_interest: 'Number Theory'},
  {last_name: 'Turing', area_interest: 'Algorithms'},
  {last_name: 'Galois', area_interest: 'Logic'},
]
puts people.sort_by {|person| [
  Descending.new(person[:last_name]),  # <---------
  person[:area_interest],
]}

输出:

{:last_name=>"Turing", :area_interest=>"Algorithms"}
{:last_name=>"Russell", :area_interest=>"Logic"}
{:last_name=>"Gauss", :area_interest=>"Number Theory"}
{:last_name=>"Galois", :area_interest=>"Abstract Algebra"}
{:last_name=>"Galois", :area_interest=>"Logic"}
{:last_name=>"Euler", :area_interest=>"Graph Theory"}

顺便说一下,如果您想要按降序排序的对象是一个数值类型,那么您可以简单地使用一元运算符-

people.sort_by {|person| [-person.age, person.name] }

你很快!我会去尝试一下。 - diek
有其他两列的话,会有影响吗?我能够将您的代码完美地运行起来,但在我的代码中实现时,它并没有按照预期工作。代码: http://paste.fedoraproject.org/81568/CSV: http://paste.fedoraproject.org/81569/ - diek
如果这太难处理了,别担心,你已经帮了我很多,我很感激。 - diek
@diek,你想按first_name排序,不是last_name,是吗?请将Descending.new(person[:last_name])替换为Descending.new(person[:first_name]) - falsetru
我这周一直在忙,错过了休息。我需要小小的休息。谢谢。 - diek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接