Bagaimana saya bisa menggunakan cara ini untuk menjumlahkan atribut dari objek. Array saya [product1, product2] Saya ingin menjumlahkan product1.price + product2.price. Apakah mungkin menggunakan array.inject (: +)?
Pablo Cantero
7
Anda dapat menggunakan trik serupa dengan metode peta: array.map (&: price) .inject (: +)
markquezada
100
array.map(&:price).inject(0, :+)sedikit lebih aman. Itu memastikan bahwa jika Anda memiliki daftar kosong Anda mendapatkan 0 bukannya nihil .
johnf
11
menggunakan array.map (...). inject (...) tidak efisien, Anda akan mengulangi semua data dua kali. Coba array.inject(0) { |sum, product| sum += product.price }
Sementara setara dengan array.inject(0, :+), pengurangan kata memasuki bahasa yang lebih umum dengan munculnya model pemrograman MapReduce .
menyuntikkan , mengurangi , melipat , menumpuk , dan mengompres semuanya identik sebagai kelas fungsi lipat . Saya menemukan konsistensi di seluruh basis kode Anda yang paling penting, tetapi karena berbagai komunitas cenderung lebih suka satu kata dari yang lain, tetap berguna untuk mengetahui alternatifnya.
Untuk menekankan verbiage pengurangan peta, berikut adalah versi yang sedikit lebih memaafkan pada apa yang berakhir di array itu.
Saya setuju, reduceceritakan lebih banyak tentang apa fungsinya, tetapi injectterdengar lebih keren.
everett1992
1
Setuju dengan komentar terakhir, Anda memberi saya jawaban terbaik.
Jerska
1
Satu komentar yang akan saya sampaikan adalah bahwa reducedan mapketika fungsi tingkat tinggi mendahului MapReduce. Inspirasi berjalan sebaliknya. Dan dalam pengertian MapReduce, ini adalah operasi yang agak berbeda dari pengurangan fungsional sederhana, memiliki implikasi untuk bagaimana mesin yang berbeda berkomunikasi.
acjay
Ken Iverson memperkenalkan operator / disebut "operator reduksi" dalam bahasa pemrograman APL. Sumber: Iverson, Kenneth. 1962. Bahasa Pemrograman. Wiley. Sumber lain: "Notasi sebagai Alat Pemikiran", 1979 ACM Turing Award Lecture, Kenneth E. Iverson, dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf
Fernando Pelliccioni
112
Atau (hanya untuk perbandingan), jika Anda memasang Rails (sebenarnya hanya ActiveSupport):
Versi activesupport yang lebih baru sebenarnya tidak memuat semua ekstensi secara default. Anda akan ingin baik memerlukan hanya jumlah modul: require 'active_support/core_ext/enumerable.rb', atau memerlukan semua dukungan aktif: require 'active_support/all'. Lebih lanjut tentang ini di sini: API Documents
dcashman
2
Tak peduli bahwa activesupportadalah besar ketergantungan untuk tarik ke sebuah proyek untuk pergi dari array.inject(:+)ke array.sum.
meagar
1
Nitpick komentar yang baik: seharusnya require 'active_support/core_ext/enumerable'tanpa .rbakhiran, karena ditambahkan secara implisit.
Per Lundberg
72
Untuk Ruby> = 2.4.0 Anda dapat menggunakan sumdari Enumerables.
[1,2,3,4].sum
Berbahaya untuk mokeypatch kelas dasar. Jika Anda suka bahaya dan menggunakan versi Ruby yang lebih lama, Anda bisa menambahkan #sumke Arraykelas:
classArraydef sum
inject(0){|sum, x| sum + x }endend
Maksudnya adalah bahwa Anda tidak perlu melakukan Patch Monyet untuk Ruby> = 2.4, dan bahwa patch monyet berbahaya, dan bahwa Anda sekarang dapat menjumlahkan enumerable secara native, tetapi ada juga cara untuk mendukung fungsi tersebut.
Peter H. Boling
Diturunkan karena implementasi Anda mengembalikan nol pada array kosong.
Eldritch Conundrum
45
Baru untuk Ruby 2.4.0
Anda dapat menggunakan metode yang dinamai tepat Enumerable#sum. Ini memiliki banyak keunggulan dibandingkan inject(:+)tetapi ada beberapa catatan penting untuk dibaca di akhir juga.
Metode ini tidak setara dengan #inject(:+). Sebagai contoh
%w(a b c).inject(:+)#=> "abc"%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
Juga,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)(1..1000000000).inject(:+)#=> 500000000500000000 (execution time: upwards of a minute)
Lihat jawaban ini untuk informasi lebih lanjut tentang mengapa sumseperti ini.
Ruby 2.4.0 dirilis hari ini dengan fitur ini disertakan! 🎉
amoebe
@amoebe kamu benar! Senang melihat fitur bermanfaat ini dimasukkan.
kumpulkan
19
Hanya demi keberagaman, Anda juga dapat melakukan ini jika array Anda bukan array angka, melainkan array objek yang memiliki properti yang berupa angka (misalnya jumlah):
Ini sama dengan melakukan: array.map(&:amount).inject(0, :+). Lihat jawaban lain.
Richard Jones
4
Di satu sisi, ya. Namun, menggunakan mapkemudian injectmengharuskan Anda untuk mengulang array dua kali: sekali untuk membuat array baru, yang lain untuk menjumlahkan anggota. Metode ini sedikit lebih verbose, tetapi juga lebih efisien.
Juga memungkinkan untuk [1,2].sum{|x| x * 2 } == 6:
# http://madeofcode.com/posts/74-ruby-core-extension-array-sumclassArraydef sum(method =nil,&block)if block_given?
raise ArgumentError,"You cannot pass a block and a method!"if method
inject(0){|sum, i| sum +yield(i)}elsif method
inject(0){|sum, i| sum + i.send(method)}else
inject(0){|sum, i| sum + i }endendend
Ini akan membuat string "123 + 321 + 12389" dan kemudian gunakan fungsi eval untuk melakukan penjumlahan. Ini hanya untuk tujuan bermain golf , Anda tidak boleh menggunakannya dalam kode yang tepat.
[1] pry(main)>[1,2,3,4].sum
=>10[2] pry(main)>[].sum
=>0[3] pry(main)>[1,2,3,5,nil].sum
TypeError:nil can't be coerced into Integer
Metode 2:
[24] pry(main)>[].inject(:+)=>nil[25] pry(main)>[].inject(0,:+)=>0[4] pry(main)>[1,2,3,4,5].inject(0,:+)=>15[5] pry(main)>[1,2,3,4,nil].inject(0,:+)TypeError:nil can't be coerced into Integer
from (pry):5:in `+'
Metode 3:
[6] pry(main)>[1,2,3].reduce(:+)=>6[9] pry(main)>[].reduce(:+)=>nil[7] pry(main)>[1,2,nil].reduce(:+)TypeError:nil can't be coerced into Integer
from (pry):7:in `+'
Metode 4:
Ketika Array berisi nihil dan nilai kosong, secara default jika Anda menggunakan fungsi di atas mengurangi, menjumlahkan, menyuntikkan semuanya akan melalui
TypeError: nil tidak bisa dipaksa menjadi Integer
Anda dapat mengatasi ini dengan,
[16] pry(main)> sum =0=>0[17] pry(main)>[1,2,3,4,nil,''].each{|a| sum+= a.to_i }=>[1,2,3,4,nil,""][18] pry(main)> sum
=>10
Metode 6: eval
Mengevaluasi ekspresi Ruby dalam string.
[26] pry(main)> a =[1,3,4,5]=>[1,3,4,5][27] pry(main)> eval a.join '+'=>13[30] pry(main)> a =[1,3,4,5,nil]=>[1,3,4,5,nil][31] pry(main)> eval a.join '+'SyntaxError:(eval):1: syntax error, unexpected end-of-input
1+3+4+5+
array.sum
Jawaban:
Coba ini:
Lihat Dokumentasi Enumerable Ruby
(catatan:
0
case dasar diperlukan sehingga0
akan dikembalikan pada array kosong bukannil
)sumber
array.inject(:+)
lebih efisien.array.inject(:+)
tampaknya menyebabkan masalah di Ruby 1.8.6 Pengecualian "LocalJumpError: no block diberikan" mungkin muncul.array.sum
mungkin memberi Anda jumlah nilai array.reduce
, yang merupakan alias dariinject
(seperti padaarray.reduce( :+ )
).inject
daripadareduce
.Atau coba cara Ruby 1.9:
Catatan:
0
case dasar diperlukan jika tidaknil
akan dikembalikan pada array kosong:sumber
array.map(&:price).inject(0, :+)
sedikit lebih aman. Itu memastikan bahwa jika Anda memiliki daftar kosong Anda mendapatkan 0 bukannya nihil .array.inject(0) { |sum, product| sum += product.price }
Sementara setara dengan
array.inject(0, :+)
, pengurangan kata memasuki bahasa yang lebih umum dengan munculnya model pemrograman MapReduce .menyuntikkan , mengurangi , melipat , menumpuk , dan mengompres semuanya identik sebagai kelas fungsi lipat . Saya menemukan konsistensi di seluruh basis kode Anda yang paling penting, tetapi karena berbagai komunitas cenderung lebih suka satu kata dari yang lain, tetap berguna untuk mengetahui alternatifnya.
Untuk menekankan verbiage pengurangan peta, berikut adalah versi yang sedikit lebih memaafkan pada apa yang berakhir di array itu.
Beberapa bacaan tambahan yang relevan:
sumber
reduce
ceritakan lebih banyak tentang apa fungsinya, tetapiinject
terdengar lebih keren.reduce
danmap
ketika fungsi tingkat tinggi mendahului MapReduce. Inspirasi berjalan sebaliknya. Dan dalam pengertian MapReduce, ini adalah operasi yang agak berbeda dari pengurangan fungsional sederhana, memiliki implikasi untuk bagaimana mesin yang berbeda berkomunikasi.Atau (hanya untuk perbandingan), jika Anda memasang Rails (sebenarnya hanya ActiveSupport):
sumber
require 'active_support/core_ext/enumerable.rb'
, atau memerlukan semua dukungan aktif:require 'active_support/all'
. Lebih lanjut tentang ini di sini: API Documentsactivesupport
adalah besar ketergantungan untuk tarik ke sebuah proyek untuk pergi dariarray.inject(:+)
kearray.sum
.require 'active_support/core_ext/enumerable'
tanpa.rb
akhiran, karena ditambahkan secara implisit.Untuk Ruby> = 2.4.0 Anda dapat menggunakan
sum
dari Enumerables.Berbahaya untuk mokeypatch kelas dasar. Jika Anda suka bahaya dan menggunakan versi Ruby yang lebih lama, Anda bisa menambahkan
#sum
keArray
kelas:sumber
Baru untuk Ruby 2.4.0
Anda dapat menggunakan metode yang dinamai tepat
Enumerable#sum
. Ini memiliki banyak keunggulan dibandingkaninject(:+)
tetapi ada beberapa catatan penting untuk dibaca di akhir juga.Contohnya
Kisaran
Array
Catatan penting
Metode ini tidak setara dengan
#inject(:+)
. Sebagai contohJuga,
Lihat jawaban ini untuk informasi lebih lanjut tentang mengapa
sum
seperti ini.sumber
Ruby 2.4+ / Rails -
array.sum
mis[1, 2, 3].sum # => 6
Ruby pre 2.4 -
array.inject(:+)
atauarray.reduce(:+)
* Catatan:
#sum
Metode ini merupakan tambahan baru untuk 2.4enumerable
sehingga Anda sekarang dapat menggunakanarray.sum
ruby murni, bukan hanya Rails.sumber
Hanya demi keberagaman, Anda juga dapat melakukan ini jika array Anda bukan array angka, melainkan array objek yang memiliki properti yang berupa angka (misalnya jumlah):
sumber
array.map(&:amount).inject(0, :+)
. Lihat jawaban lain.map
kemudianinject
mengharuskan Anda untuk mengulang array dua kali: sekali untuk membuat array baru, yang lain untuk menjumlahkan anggota. Metode ini sedikit lebih verbose, tetapi juga lebih efisien.Cara ruby ​​1.8.7 adalah sebagai berikut:
sumber
Anda cukup menggunakan:
sumber
inject(:+)
tetapi ini tidakinject :+
?Ini cukup
[1,2,3].inject('+')
sumber
Ruby 2.4.0 dirilis, dan ia memiliki metode # jumlah Enumerable . Jadi kamu bisa melakukannya
Contoh dari dokumen:
sumber
Juga memungkinkan untuk
[1,2].sum{|x| x * 2 } == 6
:sumber
untuk array dengan nilai nil kita bisa melakukan compact dan kemudian menyuntikkan jumlah ex
sumber
Bekerja untuk Ranges juga ... karenanya,
sumber
Jika Anda merasa golf, Anda bisa melakukannya
Ini akan membuat string "123 + 321 + 12389" dan kemudian gunakan fungsi eval untuk melakukan penjumlahan. Ini hanya untuk tujuan bermain golf , Anda tidak boleh menggunakannya dalam kode yang tepat.
sumber
Metode 1:
Metode 2:
Metode 3:
Metode 4: Ketika Array berisi nihil dan nilai kosong, secara default jika Anda menggunakan fungsi di atas mengurangi, menjumlahkan, menyuntikkan semuanya akan melalui
Anda dapat mengatasi ini dengan,
Metode 6: eval
Mengevaluasi ekspresi Ruby dalam string.
sumber
3 cara yang bisa kita lakukan jumlah array
1)
array.inject(0){|sum,x| sum + x }
2)
array.inject('+')
3)
array.join('+')
sumber
Atau Anda dapat mencoba metode ini:
sumber
Ini jalan terpendek. Cobalah.
array.inject :+
sumber
* Ini bekerja dengan baik untuk saya sebagai pengembang baru. Anda dapat menyesuaikan rentang angka dengan mengubah nilai dalam []
sumber
Anda juga bisa melakukannya dengan mudah
sumber
Anda dapat menggunakan .map dan .sum seperti:
sumber
array.sum