¿Qué es el operador Ruby <=> (nave espacial)?
¿ Qué es el operador Ruby <=>
(nave espacial)? ¿El operador está implementado en otros idiomas?
El operador de la nave espacial devolverá 1
, 0
o −1
dependiendo del valor del argumento izquierdo en relación con el argumento derecho.
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
Se usa comúnmente para ordenar datos.
También se le conoce como operador de comparación tripartita . Perl fue probablemente el primer lenguaje en usarlo. Algunos otros lenguajes que lo admiten son Apache Groovy, PHP 7+ y C++20.
El método de la nave espacial es útil cuando lo defines en tu propia clase e incluyes el módulo Comparable . Luego, su clase obtiene los >, < , >=, <=, ==, and between?
métodos de forma gratuita.
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>]
Es un operador de comparación general. Devuelve -1, 0 o +1 dependiendo de si su receptor es menor, igual o mayor que su argumento.
Te lo explicaré con un ejemplo sencillo.
[1,3,2] <=> [2,2,2]
Ruby comenzará a comparar cada elemento de ambas matrices desde el lado izquierdo.
1
porque la matriz izquierda es más pequeña que2
la matriz derecha. Por lo tanto, la matriz izquierda es más pequeña que la matriz derecha. La salida será-1
.[2,3,2] <=> [2,2,2]
Como se indicó anteriormente, primero comparará el primer elemento que es igual y luego comparará el segundo elemento; en este caso, el segundo elemento de la matriz izquierda es mayor, por lo tanto, la salida es
1
.
Dado que este operador reduce las comparaciones a una expresión entera, proporciona la forma más general de ordenar de forma ascendente o descendente basándose en múltiples columnas/atributos.
Por ejemplo, si tengo una serie de objetos puedo hacer cosas como esta:
# `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
Este patrón básico se puede generalizar para ordenar por cualquier número de columnas, en cualquier permutación de ascendente/descendente en cada una.