Ruby <=>(宇宙船)演算子とは何ですか?


262

Ruby <=>(宇宙船)オペレーターとは何ですか?演算子は他の言語で実装されていますか?


1
では、配列の比較についてはどうですか?それは大きい場合は1、小さい場合は-1、0を返し等しい場合、要素ごとに比較し、」本の中で言ったが、何について[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です。これは基本的には最悪です。
クリフォードヒース

アルゴリズムの一貫性のために[1,nil] <=> [1,3]得られるような配列を比較する場合nil<=>結果がNOT になるまで各要素を順番に比較します0。この例では、Rubyが「より小さい」または「より大きい」を宣言する方法はありません。比較を行うことができないからです。nil「等しくない」として扱われるべきです。データについて何かを知っていて、たとえばnilとして扱いたい0場合、Rubyはそれを簡単にします。
リロール2017

回答:


359

PerlはおそらくPerlを最初に使用した言語です。Groovyはそれをサポートするもう1つの言語です。基本的に代わりに返す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の非常にエレガントなバージョンだと思います。
マイクリーデル2009年

12
c#のアナログはIComparable.CompareTo
Sergey Mirvoda、2009

1
実際には、負または正の値が返されると思います。0は依然として平等を意味します。
超照明

1
@superluminary Cのstrcmp関数とは異なり、x <=> yは、xとyが(Rubyおよびそれを使用する他の言語で)比較できない場合にのみ-1、0、1、またはnilを返すように特別に設計されています。これにより、RubyのComparableミックスインなどの演算子のオーバーロードが容易になります。演算子が最も可能性の高いPerlで、主に「sort BLOCK LIST」構文を簡略化するために使用されました。BLOCKは、リスト項目のソート方法に応じて、正の数、負の数、または0を返すことができるサブルーチンです。宇宙船のオペレーターは、ブロックで使用すると便利です。
TonyArra 2013

2
比較した2つのオブジェクトが比較できない場合は、nilが表示されます
gamov 2014年

70

宇宙船メソッドは、独自のクラスで定義し、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]

    上記のように、最初に等しい最初の要素を比較し、次に2番目の要素を比較します。この場合、左の配列の2番目の要素の方が大きいため、出力は1です。


各配列の最初の左の要素を比較するだけですか、それとも他の要素も比較し続けますか?良い説明
Kick Buttowski

1
@KickButtowskiは、等しくない数が見つからない限り、他の要素を比較し続けます。
Anil Maurya

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)とまったく同じです。結果の符号は、それをascまたはdescにするものです。
リロール

いいえ、それは非常に重要です。zipの係数は他のすべての係数の(絶対)合計よりも大きくする必要があり、年齢の係数は最後と最初の係数の(絶対)合計よりも大きくする必要があります。そして、それを満足する最小の数列は、2の累乗の数列です。ところで、私のコメントを注意深く読むと、マイナス記号が含まれていることが
Elmar Zander

1
それでは、もう少し詳しく説明します。因数(4、-3,2,1)と宇宙船の演算結果(1,1、-1、-1)を使用すると、加重和は-2になりますが、ポジティブである必要があります!そうしないと、大きい方のジップが小さい方のジッパーの前に来ます。これは、要因(8、-4、2、1)では発生しません。
Elmar Zander

1
ああ、なるほど。2列以上で並べ替える場合は、2の累乗が必要です。これを修正するのを助けてくれてありがとう。3つ以上の列の並べ替えが間違っていることが判明した場合は、申し訳ありません。
リロール

-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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.