Em programação, além dos operadores de comparação mais comuns, como <
, >
ou ==
, em algumas linguagens podemos encontrar o Spaceship Operator <=>
, que faz uma "comparação de três vias": são realizadas três comparações entre dois valores numa única operação utilizando os operadores <
, ==
e >
. Mas o que isso significa? Em resumo, dado a <=> b
os valores são comparados e um resultado diferente será retornado dependendo da relação entre eles:
retorna -1 | se a < b |
retorna 0 | se a == b |
retorna 1 | se a > b |
Vamos ver alguns exemplos simples:
1 <=> 2
# => -1
# já que 1 < 2, o retorno é -1
2 <=> 1
# => 1
# como 2 é maior que 1, o retorno é 1
1 <=> 1
# => 0
# quando os valores comparados são iguais, o retorno é 0
Esse operador nos dá resultados interessantes quando usados de outras maneiras. Vamos, por exemplo, usar o <=>
junto ao método group_by
:
Array(1..10).group_by { |n| n <=> 5 }
# => {-1=>[1, 2, 3, 4], 0=>[5], 1=>[6, 7, 8, 9, 10]}
Note como o retorno foi uma Hash que separa os números em três grupos de acordo com sua relação com o valor de referência, nesse caso o 5.
Talvez o mais interessante seja a forma como o Spaceship Operator interage com o método sort
:
["coelho", "gato", "cavalo", "zebra", "ema"].sort { |a, b| a <=> b }
# => ["cavalo", "coelho", "ema", "gato", "zebra"]
["coelho", "gato", "cavalo", "zebra", "ema"].sort { |a, b| b <=> a }
# => ["zebra", "gato", "ema", "coelho", "cavalo"]
O primeiro exemplo, usando a <=> b
, ordena as palavras em ordem alfabética e o segundo, com b <=> a
, na ordem inversa. Isso acontece porque alterando a ordem de a
e b
, os retornos são diametralmente opostos. Essa estrutura pode ser adaptada para todo tipo de ordenação personalizada, atentando somente ao fato de que em comparações que resultam em 0
, a ordem dos elementos pode ser imprevisível. No exemplo abaixo, por exemplo, as palavras "cavalo" e "coelho" permanecem na mesma ordem em que se encontram no array original:
["coelho", "gato", "cavalo", "zebra", "ema"].sort { |a, b| a.length <=> b.length }
# => ["ema", "gato", "zebra", "coelho", "cavalo"]
["coelho", "gato", "cavalo", "zebra", "ema"].sort { |a, b| b.length <=> a.length }
# => ["coelho", "cavalo", "zebra", "gato", "ema"]
Em alguns casos, como no exemplo acima, será mais fácil utilizar o método sort_by
e passar a ele apenas um objeto com o critério de ordenação desejado. Por exemplo:
["coelho", "gato", "cavalo", "zebra", "ema"].sort_by { |a| a.length }
# => ["ema", "gato", "zebra", "coelho", "cavalo"]
Além disso, se o seu objetivo for separar elementos de um Array ou String de acordo com um determinado critério, você pode tentar usar o método partition
(Enumerable, String).