[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
Saya melihat kode ini tetapi otak saya tidak mendaftarkan bagaimana angka 10 dapat menjadi hasilnya. Adakah yang mau menjelaskan apa yang terjadi di sini?
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
Saya melihat kode ini tetapi otak saya tidak mendaftarkan bagaimana angka 10 dapat menjadi hasilnya. Adakah yang mau menjelaskan apa yang terjadi di sini?
Jawaban:
Anda dapat menganggap argumen blok pertama sebagai akumulator: hasil dari setiap run blok disimpan dalam akumulator dan kemudian diteruskan ke eksekusi berikutnya dari blok. Dalam kasus kode yang ditunjukkan di atas, Anda default akumulator, hasil, ke 0. Setiap menjalankan blok menambahkan nomor yang diberikan ke total saat ini dan kemudian menyimpan hasilnya kembali ke akumulator. Panggilan blok berikutnya memiliki nilai baru ini, menambahnya, menyimpannya lagi, dan mengulanginya.
Pada akhir proses, menyuntikkan kembali akumulator, yang dalam hal ini adalah jumlah semua nilai dalam array, atau 10.
Berikut adalah contoh sederhana lain untuk membuat hash dari array objek, dikunci oleh representasi string mereka:
[1,"a",Object.new,:hi].inject({}) do |hash, item|
hash[item.to_s] = item
hash
end
Dalam hal ini, kami menyetel akumulator kami ke hash kosong, lalu mengisinya setiap kali blok dijalankan. Perhatikan kita harus mengembalikan hash sebagai baris terakhir dari blok, karena hasil dari blok akan disimpan kembali di akumulator.
result + explanation
adalah transformasi ke akumulator dan nilai kembali. Ini adalah baris terakhir di blok yang membuatnya kembali secara implisit.
inject
mengambil nilai untuk memulai dengan ( 0
dalam contoh Anda), dan sebuah blok, dan menjalankan blok itu sekali untuk setiap elemen daftar.
result + element
).Cara termudah untuk menjelaskan ini adalah dengan menunjukkan cara kerja setiap langkah, misalnya Anda; ini adalah serangkaian langkah imajiner yang menunjukkan bagaimana hasil ini dapat dievaluasi:
[1, 2, 3, 4].inject(0) { |result, element| result + element }
[2, 3, 4].inject(0 + 1) { |result, element| result + element }
[3, 4].inject((0 + 1) + 2) { |result, element| result + element }
[4].inject(((0 + 1) + 2) + 3) { |result, element| result + element }
[].inject((((0 + 1) + 2) + 3) + 4) { |result, element| result + element }
(((0 + 1) + 2) + 3) + 4
10
Sintaks untuk metode injeksi adalah sebagai berikut:
inject (value_initial) { |result_memo, object| block }
Mari kita pecahkan contoh di atas yaitu
[1, 2, 3, 4].inject(0) { |result, element| result + element }
yang memberikan 10 sebagai output.
Jadi, sebelum memulai, mari kita lihat apa saja nilai yang disimpan di setiap variabel:
hasil = 0 Nol berasal dari inject (nilai) yaitu 0
element = 1 Ini adalah elemen pertama dari array.
Oke !!! Jadi, mari kita mulai memahami contoh di atas
Langkah 1 [1, 2, 3, 4].inject(0) { |0, 1| 0 + 1 }
Langkah 2 [1, 2, 3, 4].inject(0) { |1, 2| 1 + 2 }
Langkah: 3 [1, 2, 3, 4].inject(0) { |3, 3| 3 + 3 }
Langkah: 4 [1, 2, 3, 4].inject(0) { |6, 4| 6 + 4 }
Langkah: 5 [1, 2, 3, 4].inject(0) { |10, Now no elements left in the array, so it'll return 10 from this step| }
Di sini nilai Bold-Italic adalah elemen yang diambil dari array dan nilai Bold sederhana adalah nilai yang dihasilkan.
Saya harap Anda memahami cara kerja #inject
metode #ruby
.
Kode ini mengulangi empat elemen dalam array dan menambahkan hasil sebelumnya ke elemen saat ini:
Apa yang mereka katakan, tetapi perhatikan juga bahwa Anda tidak selalu perlu memberikan "nilai awal":
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
sama dengan
[1, 2, 3, 4].inject { |result, element| result + element } # => 10
Cobalah, saya akan menunggu.
Ketika tidak ada argumen yang diteruskan untuk menyuntikkan, dua elemen pertama dilewatkan ke dalam iterasi pertama. Dalam contoh di atas, hasilnya adalah 1 dan elemen adalah 2 pertama kalinya, jadi satu panggilan kurang dibuat ke blok.
Jumlah yang Anda masukkan ke dalam () injeksi Anda mewakili tempat awal, bisa 0 atau 1000. Di dalam pipa Anda memiliki dua tempat penampung | x, y |. x = berapa nomor yang Anda miliki di dalam .inject ('x'), dan secound mewakili setiap iterasi objek Anda.
[1, 2, 3, 4].inject(5) { |result, element| result + element } # => 15
1 + 5 = 6 2 + 6 = 8 3 + 8 = 11 11 + 4 = 15
Suntikan menerapkan blok
result + element
untuk setiap item dalam array. Untuk item berikutnya ("elemen"), nilai yang dikembalikan dari blok adalah "hasil". Cara Anda menyebutnya (dengan parameter), "hasil" dimulai dengan nilai parameter itu. Jadi efeknya menambahkan elemen ke atas.
tldr; inject
berbeda dari map
dalam satu cara penting: inject
mengembalikan nilai eksekusi terakhir dari blok sedangkan map
mengembalikan array yang diulangi.
Lebih dari itu nilai setiap eksekusi blok dilewatkan ke eksekusi berikutnya melalui parameter pertama ( result
dalam hal ini) dan Anda dapat menginisialisasi nilai itu ( (0)
bagian).
Contoh Anda di atas dapat ditulis menggunakan map
seperti ini:
result = 0 # initialize result
[1, 2, 3, 4].map { |element| result += element }
# result => 10
Efek yang sama tetapi inject
lebih ringkas di sini.
Anda akan sering menemukan tugas terjadi di map
blok, sedangkan evaluasi terjadi di inject
blok.
Metode mana yang Anda pilih tergantung pada ruang lingkup yang Anda inginkan result
. Kapan tidak menggunakannya akan menjadi sesuatu seperti ini:
result = [1, 2, 3, 4].inject(0) { |x, element| x + element }
Anda mungkin seperti semua, "Lihat saya, saya baru saja menggabungkan semuanya menjadi satu baris," tetapi Anda juga mengalokasikan memori untuk sementara x
sebagai variabel awal yang tidak diperlukan karena Anda sudah harus result
bekerja dengannya.
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
setara dengan yang berikut:
def my_function(r, e)
r+e
end
a = [1, 2, 3, 4]
result = 0
a.each do |value|
result = my_function(result, value)
end
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
Dalam bahasa Inggris biasa, Anda akan melalui (iterasi) melalui array ini ( [1,2,3,4]
). Anda akan mengulangi melalui array ini 4 kali, karena ada 4 elemen (1, 2, 3, dan 4). Metode suntikan memiliki 1 argumen (angka 0), dan Anda akan menambahkan argumen itu ke elemen 1 (0 + 1. Ini sama dengan 1). 1 disimpan di "hasil". Kemudian Anda menambahkan hasil itu (yaitu 1) ke elemen berikutnya (1 + 2. Ini adalah 3). Ini sekarang akan disimpan sebagai hasilnya. Terus: 3 + 3 sama dengan 6. Dan akhirnya, 6 + 4 sama dengan 10.
Kode ini tidak memungkinkan kemungkinan tidak melewati nilai awal, tetapi dapat membantu menjelaskan apa yang terjadi.
def incomplete_inject(enumerable, result)
enumerable.each do |item|
result = yield(result, item)
end
result
end
incomplete_inject([1,2,3,4], 0) {|result, item| result + item} # => 10
Mulai di sini dan kemudian tinjau semua metode yang mengambil blok. http://ruby-doc.org/core-2.3.3/Enumerable.html#method-i-inject
Apakah itu blok yang membingungkan Anda atau mengapa Anda memiliki nilai dalam metode ini? Pertanyaan yang bagus. Apa metode operator di sana?
result.+
Seperti apa awalnya?
#inject(0)
Bisakah kita melakukan ini?
[1, 2, 3, 4].inject(0) { |result, element| result.+ element }
Apakah ini berhasil?
[1, 2, 3, 4].inject() { |result = 0, element| result.+ element }
Anda lihat saya sedang membangun ide bahwa itu hanya menjumlahkan semua elemen array dan menghasilkan nomor dalam memo yang Anda lihat di dokumen.
Anda selalu dapat melakukan ini
[1, 2, 3, 4].each { |element| p element }
untuk melihat enumerable dari array iterasi melalui. Itu ide dasarnya.
Hanya saja menyuntikkan atau mengurangi memberi Anda memo atau akumulator yang dikirim.
Kami bisa mencoba untuk mendapatkan hasil
[1, 2, 3, 4].each { |result = 0, element| result + element }
tetapi tidak ada yang kembali jadi ini hanya bertindak sama seperti sebelumnya
[1, 2, 3, 4].each { |result = 0, element| p result + element }
di blok elemen inspektur.
Ini adalah penjelasan yang sederhana dan cukup mudah dimengerti:
Lupakan "nilai awal" karena agak membingungkan di awal.
> [1,2,3,4].inject{|a,b| a+b}
=> 10
Anda dapat memahami hal di atas sebagai: Saya menyuntikkan "mesin tambah" di antara 1,2,3,4. Artinya, itu adalah 1 ♫ 2 ♫ 3 ♫ 4 dan ♫ adalah mesin tambahan, jadi itu sama dengan 1 + 2 + 3 + 4, dan itu adalah 10.
Anda benar-benar dapat menyuntikkan +
di antara mereka:
> [1,2,3,4].inject(:+)
=> 10
dan itu seperti, menyuntikkan +
di antara 1,2,3,4, membuatnya 1 + 2 + 3 + 4 dan itu adalah 10. Ini :+
adalah cara Ruby menentukan +
dalam bentuk simbol.
Ini cukup mudah dimengerti dan intuitif. Dan jika Anda ingin menganalisis cara kerjanya langkah demi langkah, itu seperti: mengambil 1 dan 2, dan sekarang menambahkannya, dan ketika Anda memiliki hasilnya, simpan dulu (yang 3), dan sekarang, selanjutnya disimpan nilai 3 dan elemen array 3 melalui proses a + b, yaitu 6, dan sekarang menyimpan nilai ini, dan sekarang 6 dan 4 melalui proses a + b, dan 10. Anda pada dasarnya melakukan
((1 + 2) + 3) + 4
dan 10. "Nilai awal" 0
hanyalah "basis" untuk memulai. Dalam banyak kasus, Anda tidak membutuhkannya. Bayangkan jika Anda membutuhkan 1 * 2 * 3 * 4 dan itu
[1,2,3,4].inject(:*)
=> 24
dan itu dilakukan. Anda tidak perlu "nilai awal" 1
untuk melipatgandakan semuanya 1
.
Ada bentuk lain dari metode .inject () Itu sangat membantu [4,5] .inject (&: +) Itu akan menjumlahkan semua elemen area
Apakah sama dengan ini:
[1,2,3,4].inject(:+)
=> 10