ruby';s<=&燃气轮机;运算符和排序方法

ruby';s<=&燃气轮机;运算符和排序方法,ruby,spaceship-operator,Ruby,Spaceship Operator,上面,我创建了一些玩家对象,并将它们添加到以前的空数组@players中 然后,我重新定义为: player1 = Player.new("moe") player2 = Player.new("larry",60) player3 = Player.new("curly", 125) @players = [player1, player2, player3] 我在@players中的玩家对象数组是从高分到低分排序的。 我想这件看起来有点黑盒。我有点不清楚这里发生了什么。我怎样才能知道幕后发

上面,我创建了一些玩家对象,并将它们添加到以前的空数组@players中

然后,我重新定义为:

player1 = Player.new("moe")
player2 = Player.new("larry",60)
player3 = Player.new("curly", 125)
@players = [player1, player2, player3]
我在@players中的玩家对象数组是从高分到低分排序的。 我想这件看起来有点黑盒。我有点不清楚这里发生了什么。我怎样才能知道幕后发生了什么

我所知道的是,如果取两个值并使用spaceship运算符/常规比较运算符:

@players.sort
21
=> 1
1  2
=> -1
1  1
=>0
有时候,Ruby似乎有很多低层次的东西在进行,我在编程的高层次上看不到。这似乎很自然。。。但这种情况似乎特别远离排序方法的较低层次。sort如何使用spaceship操作符?为什么重新定义spaceship操作符的方式使我们现在可以对对象进行排序?

在您的示例中

2 <=> 1   
=> 1

1 <=> 2
=> -1

1 <=> 1
=>0
相当于

@players.sort
@players.sort{| x,y | x y}
元素的排序取决于
方法的返回。如果
返回
-1
第一个元素在第二个元素之前排序,如果返回
1
第二个元素在第一个元素之前排序。如果更改返回值(例如交换元素),则顺序会根据返回值而更改。

实际上是一种可枚举方法,它依赖于
的实现。从Ruby文档本身:

如果使用可枚举的#max、#min或#sort,则 集合还必须实现一个有意义的运算符,如下所示 方法依赖于集合成员之间的排序

你自己试试吧:

@players.sort { |x, y| x <=> y }
职业玩家
属性访问器:名称,:分数
def初始化(名称,分数=0)
@name=name
@分数=分数
结束
定义其他
放置调用方[0]。检查
其他分数
结束
结束
player1=玩家。新建(“moe”)
player2=Player.new(“拉里”,60岁)
player3=Player.new(“curly”,125)
@玩家=[player1,player2,player3]
放置@players.sort.inspect
#=>“player.rb:19:在'sort'中”
#=>“player.rb:19:在'sort'中”
#=> [#, #, #]
你看,当我们在
@players
数组上使用
排序
时,
Player
的对象被
调用,如果你不实现它,你可能会得到:

player.rb:14:in
sort”:将player与player进行比较失败
(ArgumentError)来自player.rb:14:in
'


这是有道理的,因为在您理解排序对象之前,对象不知道如何处理

。您需要理解Ruby中的.sort方法。如果要对5张卡片进行编号排序,您可以查看所有卡片,轻松找到最低的一张,然后选择这张作为第一张卡片(假设您是从最低到最高排序的,Ruby就是这样做的)。当你的大脑进行分类时,它可以看到一切并从那里进行分类

这里有两个主要的混淆元素很少被提及:

1) Ruby无法按照您对“排序”一词的理解进行排序。Ruby只能“交换”数组元素,并且可以“比较”数组元素

2) Ruby使用一个名为spaceship的比较运算符来属性数字,以帮助它“排序”。这些数字是-1,0,1。人们错误地认为这3个数字有助于排序(例如,如果有一个数组有3个数字,比如10,20,30,那么10将是-1,20 a 0,30 a 1,Ruby只是通过将其减少到-1,0,1来简化排序。这是错误的。Ruby不能“排序”。它只能比较)

看看宇宙飞船操作员。它是由三个单独的操作员合并成一个。当Ruby比较两个变量时,会得到其中一个数字

也就是说,“结果”是什么意思?这并不意味着其中一个变量被赋值为0,1,-1。这仅仅是一种Ruby可以接受两个变量并处理它们的方法。现在,如果您只是运行:

class Player
  attr_accessor :name, :score

  def initialize(name, score=0)
    @name = name
    @score = score  
  end

  def <=> other
    puts caller[0].inspect
    other.score <=> score
  end
end

player1 = Player.new("moe")
player2 = Player.new("larry",60)
player3 = Player.new("curly", 125)
@players = [player1, player2, player3]
puts @players.sort.inspect

#=> "player.rb:19:in `sort'"
#=> "player.rb:19:in `sort'"
#=> [#<Player:0x007fe87184bbb8 @name="curly", @score=125>, #<Player:0x007fe87184bc08 @name="larry", @score=60>, #<Player:0x007fe87184bc58 @name="moe", @score=0>]
它使用参数(例如“other”)调出“def”方法,该参数具有@players的当前对象(例如“无论当前实例对象是@players的什么,因为它是sort方法,它最终将遍历“@players”数组的所有元素)。这就像在一个类上运行put方法时,它会自动调用该类中的to_s方法。对于.sort方法,也会自动查找该方法

查看该方法内部的代码,该类中必须有一个.score实例变量(带有访问器方法)或一个.score方法。score方法的结果应该(希望)是一个字符串或数字——ruby可以“排序”的两件事。如果它是一个数字,那么Ruby使用它的“sort”操作来重新排列所有这些对象,现在它知道这些对象的哪个部分要排序(在本例中,它是.score方法或实例变量的结果)

最后,Ruby还通过将其转换为数值来按字母顺序排序。它只考虑将代码从ASCII分配给任何字母(这意味着,由于大写字母在ASCII代码图表上具有较低的数值,默认情况下,大写字母将排序为第一)


希望这有帮助

你们读过吗?超级解释的可能副本喜欢它。你们忘了一件事:若要在某个类中使用方法,你们应该在其中包含可比较的模块。
class Player
  attr_accessor :name, :score

  def initialize(name, score=0)
    @name = name
    @score = score  
  end

  def <=> other
    puts caller[0].inspect
    other.score <=> score
  end
end

player1 = Player.new("moe")
player2 = Player.new("larry",60)
player3 = Player.new("curly", 125)
@players = [player1, player2, player3]
puts @players.sort.inspect

#=> "player.rb:19:in `sort'"
#=> "player.rb:19:in `sort'"
#=> [#<Player:0x007fe87184bbb8 @name="curly", @score=125>, #<Player:0x007fe87184bc08 @name="larry", @score=60>, #<Player:0x007fe87184bc58 @name="moe", @score=0>]
puts 4 <=> 5
foo = [4, 5, 6]
puts foo.sort {|a,b| a <=> b}
bar = [5, 1, 9]
puts bar.sort {|a,b| b <=> a}   
def <=>(other)
    other.score <=> score
end 
@players.sort