Ruby on Rails : Menghitung Total Penjumlahan
Setelah sekian lama menistakan diri sendiri dengan tidak menulis blog, akhirnya pada kesempatan kali ini saya ingin menulis lagi. saya agak bingung mengubah sum jadi bahasa Indonesia, maksud dari kata Total Penjumlahan itu adalah sum. Simple aja ya ! Hehehe
Kita semua pasti dihadapkan oleh operasi sum dalam pengerjaan aplikasi. Namun, apakah yang selama ini kita lakukan sudah benar? Mari kita bahas satu per satu.
Di dalam Rails, kita semua tahu kalau ActiveRecord method sum memang didesain untuk memanggil query select sum(x) from table_y. Kalau dibandingkan dengan looping manual, method tersebut jauh lebih efektif dan efisien. Meskipun begitu, tidak ada salahnya untuk kita benchmark. Tools yang digunakan untuk benchmark adalah benchmark-ips.
Terlebih dalulu install gem benchmark-ips :
gem install benchmark-ips
Sekarang kita bandingkan method sum dengan penjumlahan manual dengan menggunakan looping. Method sum kita definisikan sebagai method1 dan looping manual sebagai method2. Masuk ke console rails dan require benchmark/ips. Sebagai contoh, saya menggunakan model AdditionalPoint dan atribut point di dalamnya.
def method1
AdditionalPoint.sum(:point)
end
def method2
pts = 0
AdditionalPoint.pluck(:point).each do |p|
pts += p
end
end
Kemudian kita bandingkan 2 method tersebut :
Benchmark.ips do |x|
x.report('menggunakan method sum') { method1 }
x.report('manual looping') { method2 }
x.compare!
end
Bagaimanakah hasilnya ?
Dari gambar di atas bisa kita simpulkan jika menjumlahkan nilai dengan manual looping 3.79x lebih lambat dibandingkan method sum.
Ada beberapa alasan mengapa kita lebih baik menghindari penjumlahan manual :
- Proses penjumlahan berada di Ruby, memakan banyak RAM. Dengan menggunakan method sum kita menjumlahkan nilai di database, bukan di Ruby.
- Proses lebih lambat.
- Kode terlalu panjang dan prosedural.
Benchmark di atas ditujukan spesifik untuk Ruby on Rails. Bagaimana cara menghitung total penjumlahan di dalam pure Ruby? Asumsikan kita punya array dengan 1000 elemen dan kita ingin menjumlahkan semua nilai tersebut. Mari kita lakukan dengan beberapa cara :
Inject symbol (ekuivalen dengan reduce)
def sum_method_1
((1..1000).to_a).inject(:+)
end
Inject ke proc
def sum_method_2
((1..1000).to_a).inject(&:+)
end
Inject dengan menggunakan block
def sum_method_3
((1..1000).to_a).inject { |a, i| a + i }
end
Looping dan map
def sum_method_4
sum = 0
((1..1000).to_a).map { |a| sum += a }
sum
end
Menggunakan eval
def sum_method_5
eval ((1..1000).to_a).join("+")
end
Lalu benchmark semua method :
Benchmark.ips do |x|
x.report('inject ke symbol') { sum_method_1 }
x.report('inject ke proc') { sum_method_2 }
x.report('inject ke block') { sum_method_3 }
x.report('map dan loop') { sum_method_4 }
x.report('jadikan string kemudian eval') { sum_method_5 }
x.compare!
end
Bagaimana hasilnya?
Dari perbandingan tersebut, method inject dengan symbol adalah method yang paling efisien. Meskipun looping manual tidak memiliki perbedaan signifikan dengan method inject, menggunakan looping manual tidak dianjurkan. Inject dengan menggunakan block dan proc lebih lambat dibandingkan dengan inject dengan menggunakan symbol.
Kesimpulan yang dapat kita ambil yaitu, untuk menjumlahkan nilai dalam array kita dapat menggunakan method :
your_array.inject(:+)
comments powered by Disqus