Jika kamu buka program irb
yang secara default sepaket dengan instalasi bahasa Ruby, kemudian ketik kode sederhana seperti ini
1 |
"ruby" > "javascript" |
Output yang didapatkan adalah true
.
Tahu kenapa hasilnya true
?
String di Ruby dibandingkan dengan mengurutkan secara alfabetis. Karena r
huruf depan kata ruby
muncul lebih kemudian dari j
dari javascript
secara alfabetis, otomatis ruby
> javascript
.
Kalau tidak percaya, sekarang coba ubah jadi
1 |
"rubi" > "ruby" |
Hasilnya false
karena jelas i
lebih dulu muncul dari pada y
yang artinya i
tidak lebih besar dari y
.
Memang membingungkan kalau kita tidak tahu objek string dibandingkan berdasarkan apa tapi dari sini kita tahu berarti kalau kita membuat sebuah tipe objek sendiri alias membuat kelas, kita bisa membandingkan objek antar kelas tersebut berdasarkan kriteria yang kita inginkan.
Ambil contoh kita punya kelas Rider
dengan propertinya name
dan point
. Pura-puranya kita membuat aplikasi sistem informasi klasemen moto gp.
1 2 3 4 5 6 7 8 |
class Rider attr_accessor :name, :point def initialize(name, point) @name = name @point = point end end |
Nah namanya klasemen, berarti kita pengen tahu dong, pembalap mana yang posisinya lebih tinggi dari yang satunya? Sampai sini make sense kan ya kenapa kita butuh membandingkan 2 objek, terutama untuk kasus kelas Rider
ini.
Misal kita punya objek untuk pembalap Rossi dan Pedrosa dengan masing-masing properti nama dan poinnya.
1 2 |
rossi = Rider.new('Rossi', 500) pedrosa = Rider.new('Pedrosa', 650) |
Sekarang kita bandingkan, apakah rossi
posisinya lebih tinggi secara klasemen dari pedrosa
. Maka serta merta kita coba membandingkan keduanya menggunakan >
.
1 |
rossi > pedrosa |
Hasilnya adalah error
1 |
undefined method '>' for #<Rider:0x000055b5ab405860 @name="Rossi", @point=500> |
Begitu juga kalau kita gunakan <
untuk membandingkan, akan muncul kesalahan lagi.
Terus solusinya gimana?
Nah ini yang ingin saya share sebenarnya dari tadi.
Kita bisa menggunakan mixin Comparable dengan cara melakukan include ke dalam kelas yang ingin dibandingkan kemudian membuat implementasi method bernama <=>
dengan kriteria perbandingan yang diinginkan.
Secara internal, method <=> dipakai oleh Ruby untuk perbandingan dan juga pengurutan. Untuk kasus ini yang perlu kita pikirkan adalah cara kita membandingkan antara 2 rider.
Paling masuk akal membandingkan berdasarkan jumlah poin, semakin besar nilai poin berarti semakin besar nilai rider.
Implementasinya jadi seperti ini.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Rider include Comparable attr_accessor :name, :point def initialize(name, point) @name = name @point = point end def <=>(other) self.point <=> other.point end end |
Sekarang kita coba perbandingan yang tadi.
1 2 3 4 5 6 7 8 |
rossi = Rider.new('Rossi', 500) pedrosa = Rider.new('Pedrosa', 650) rossi > pedrosa #=> false pedrosa > rossi #=> true |
Kali ini berhasil dan didapatkan hasilnya sesuai dengan ekspektasi.
Bonus, tadi saya bilang kalau <=> digunakan juga untuk sorting. Sekarang kita coba
1 2 3 4 5 6 7 8 9 10 11 12 13 |
rossi = Rider.new('Rossi', 500) pedrosa = Rider.new('Pedrosa', 650) marquez = Rider.new('Marquez', 750) riders = [] riders << rossi riders << pedrosa riders << marquez riders.sort #=> [#<Rider:0x000055f5cb09a760 @name="Rossi", @point=500>, #<Rider:0x000055f5cb09a710 @name="Pedrosa", @point=650>, #<Rider:0x000055f5cb09a6c0 @name="Marquez", @point=750>] |
Secara default diurutkan secara ascending. Kalau mau descending berarti perlu dibalik perbandingannya jadi
1 |
riders.sort { |x,y| y <=> x } |
Perhatikan letak x
dan y
yang ditukar.