Ruby <=>(太空飞船)运算符是什么?


262

什么是Ruby <=>(太空飞船)运算符?运算符是否由其他任何语言实现?


1
现在如何比较数组呢?它在书中说:“通过对比元素元素,如果相等,则返回0,-1,如果较小,1,如果更大,但怎么样[1,3,2] <=> [2,2,2]
SF。

3
@SF,当人们比较数组时,它们通常意味着按字典顺序进行比较(就像在字典中一样,即[1,3,2] <[2,2,2],因为第一个元素是不同的)。很少(在Matlab中为fe)数组比较返回每个元素一个结果数组。在这种情况下:[-1,1,0]。
liori

请注意,如果任何nil之前的元素不同,则包含nil元素的数组是可比较的,如果必须将nil与非nil比较,则该数组是不可比较的。即[1,nil] <=> [2,3] => -1,但[1,nil] <=> [1,3] => nil。基本上,这很烂。
cliffordheath

当比较数组时,由于算法的一致性,[1,nil] <=> [1,3]得到a时nil,请依次比较每个元素,直到<=>结果为NOT 0。在此示例中,Ruby无法声明小于或大于。因为无法进行比较。的nil应视为“不相等”。如果您对数据有所了解,例如想要将其nil视为0,那么Ruby会使其变得容易。
lilole

Answers:


359

Perl可能是使用它的第一语言。Groovy是支持它的另一种语言。基本上,而不是返回1true)或0false取决于参数是否相等或不相等),飞船运算符将返回10或者−1取决于相对于右参数左边参数的值。

a <=> b :=
  if a < b then return -1
  if a = b then return  0
  if a > b then return  1
  if a and b are not comparable then return nil

这对排序数组很有用。


27
究竟。我认为它是Java的Comparable的非常优雅的版本。
Mike Reedell,2009年

12
C#中的模拟是IComparable.CompareTo
谢尔盖·米尔沃达

1
实际上,我认为可以返回任何负值或正值。0仍然表示平等。
superluminary

1
@superluminary与C的strcmp函数不同,x <=> y专门设计为仅在x和y不具有可比性时返回-1、0、1或nil(在Ruby和其他使用AFAIK的语言中)。这使得重载操作符变得容易,例如Ruby的Comparable mixin。在Perl中,运算符最有可能起源于此,它主要用于简化“ sort BLOCK LIST”语法。BLOCK是一个子例程,可以根据列表项的排序方式返回任何正数,负数或0。太空飞船操作员在块中使用方便。
TonyArra

2
请注意,如果比较的两个对象不具有可比性,您将得到零
gamov 2014年

70

当您在自己的类中定义spaceship方法并包含Comparable模块时,该方法非常有用。然后您的班>, < , >=, <=, ==, and between?免费获得方法。

class Card
  include Comparable
  attr_reader :value

  def initialize(value)
    @value = value
  end

  def <=> (other) #1 if self>other; 0 if self==other; -1 if self<other
    self.value <=> other.value
  end

end

a = Card.new(7)
b = Card.new(10)
c = Card.new(8)

puts a > b # false
puts c.between?(a,b) # true

# Array#sort uses <=> :
p [a,b,c].sort # [#<Card:0x0000000242d298 @value=7>, #<Card:0x0000000242d248 @value=8>, #<Card:0x0000000242d270 @value=10>]

20

这是一个一般的比较运算符。根据其接收者是小于,等于还是大于其参数,它返回-1、0或+1。


18

我将用一个简单的例子来解释

  1. [1,3,2] <=> [2,2,2]

    Ruby将开始从左侧比较两个数组的每个元素。 1左数组小于2右数组。因此,左数组小于右数组。输出将是-1

  2. [2,3,2] <=> [2,2,2]

    如上所述,它将首先比较等于的第一个元素,然后将比较第二个元素,在这种情况下,左数组的第二个元素更大,因此输出为1


它只是比较每个数组的第一个左元素还是继续比较其他元素?很好的解释
Kick Buttowski

1
@KickButtowski它将继续比较其他元素,除非找到不相等的数字。
艾尼尔·莫里亚

5

由于此运算符可简化对整数表达式的比较,因此它提供了基于多列/属性对升序或降序进行排序的最通用方法。

例如,如果我有一个对象数组,则可以执行以下操作:

# `sort!` modifies array in place, avoids duplicating if it's large...

# Sort by zip code, ascending
my_objects.sort! { |a, b| a.zip <=> b.zip }

# Sort by zip code, descending
my_objects.sort! { |a, b| b.zip <=> a.zip }
# ...same as...
my_objects.sort! { |a, b| -1 * (a.zip <=> b.zip) }

# Sort by last name, then first
my_objects.sort! { |a, b| 2 * (a.last <=> b.last) + (a.first <=> b.first) }

# Sort by zip, then age descending, then last name, then first
# [Notice powers of 2 make it work for > 2 columns.]
my_objects.sort! do |a, b|
      8 * (a.zip   <=> b.zip) +
     -4 * (a.age   <=> b.age) +
      2 * (a.last  <=> b.last) +
          (a.first <=> b.first)
end

可以将这种基本模式概括为按任意数量的列进行排序,每列按升序/降序排列。


很好的例子,只是最后一个没有按预期工作。这些因子应为2的幂,以降序排列,即8,-4、2、1。您编写它的方式(因子4,-3,2,1),例如,“年龄+姓氏”比“ zip”更重要“ ...
Elmar Zander

我认为这些数字并不代表您的意思。每个因子乘以符号,该符号将为-1、0或1。2的幂在这里无关紧要。-3 *(a.age <=> b.age)与3 *(b.age <=> a.age)完全相同。结果的符号是使它升序还是降序的原因。
lilole19年

不,这很重要。zip的因子必须大于所有其他因子的(绝对)和,而年龄的因子必须大于last和first因子的(绝对)和,依此类推。满足的最小数字序列是2的幂序列。顺便说一句,如果您仔细阅读我的评论,您会发现我包括了负号...
Elmar Zander

1
好的,也许我会对此进行详细说明:使用因子(4,-3,2,1)并从飞船op(1,1,-1,-1)得出的加权总和为-2,但是它必须是积极的!否则,较大的拉链将在较小的拉链之前。因数(8,-4,2,1)不会发生这种情况。
Elmar Zander

1
嗯,我现在看到的是,如果按> 2列进行排序,则需要2的幂。感谢您帮助纠正此问题。很抱歉,如果您对3列或更多列的排序结果错误。
lilole19年

-2

什么是<=> (“太空飞船”操作员)

根据引入运算符RFC,$ a <=>$ b

 -  0 if $a == $b
 - -1 if $a < $b
 -  1 if $a > $b

 - Return 0 if values on either side are equal
 - Return 1 if value on the left is greater
 - Return -1 if the value on the right is greater

例:

//Comparing Integers

echo 1 <=> 1; //ouputs 0
echo 3 <=> 4; //outputs -1
echo 4 <=> 3; //outputs 1

//String Comparison

echo "x" <=> "x"; // 0
echo "x" <=> "y"; //-1
echo "y" <=> "x"; //1

更多:

// Integers
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// Floats
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// Strings
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1

echo "a" <=> "aa"; // -1
echo "zz" <=> "aa"; // 1

// Arrays
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1

// Objects
$a = (object) ["a" => "b"]; 
$b = (object) ["a" => "b"]; 
echo $a <=> $b; // 0
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.