[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?
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.
Namun, penjelasan yang bagus, dalam contoh yang diberikan oleh OP, apa yang dikembalikan (seperti hash ada dalam contoh Anda). Itu berakhir dengan hasil + penjelasan dan harus memiliki nilai balik, ya?
Projjol
1
@ Projjol result + explanationadalah transformasi ke akumulator dan nilai kembali. Ini adalah baris terakhir di blok yang membuatnya kembali secara implisit.
KA01
87
injectmengambil nilai untuk memulai dengan ( 0dalam contoh Anda), dan sebuah blok, dan menjalankan blok itu sekali untuk setiap elemen daftar.
Pada iterasi pertama, ia meneruskan nilai yang Anda berikan sebagai nilai awal, dan elemen pertama dari daftar, dan itu menyimpan nilai yang dikembalikan oleh blok Anda (dalam kasus ini result + element).
Kemudian menjalankan blok lagi, meneruskan hasil dari iterasi pertama sebagai argumen pertama, dan elemen kedua dari daftar sebagai argumen kedua, lagi-lagi menyimpan hasilnya.
Ini berlanjut seperti ini sampai menghabiskan semua elemen dari daftar.
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)+410
Terima kasih telah menuliskan langkah-langkahnya. Ini banyak membantu. Meskipun saya sedikit bingung tentang apakah maksud Anda diagram di bawah ini adalah bagaimana metode injeksi diterapkan di bawah dalam hal apa yang disahkan sebagai argumen untuk menyuntikkan.
2
Diagram di bawah ini didasarkan pada bagaimana bisa dilaksanakan; itu belum tentu diimplementasikan dengan cara ini. Itu sebabnya saya mengatakan itu adalah serangkaian langkah imajiner; itu menunjukkan struktur dasar, tetapi bukan implementasi yang tepat.
Brian Campbell
27
Sintaks untuk metode injeksi adalah sebagai berikut:
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
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; injectberbeda dari mapdalam satu cara penting: injectmengembalikan nilai eksekusi terakhir dari blok sedangkan mapmengembalikan array yang diulangi.
Lebih dari itu nilai setiap eksekusi blok dilewatkan ke eksekusi berikutnya melalui parameter pertama ( resultdalam hal ini) dan Anda dapat menginisialisasi nilai itu ( (0)bagian).
Contoh Anda di atas dapat ditulis menggunakan mapseperti ini:
result =0# initialize result[1,2,3,4].map {|element| result += element }# result => 10
Efek yang sama tetapi injectlebih ringkas di sini.
Anda akan sering menemukan tugas terjadi di mapblok, sedangkan evaluasi terjadi di injectblok.
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 xsebagai variabel awal yang tidak diperlukan karena Anda sudah harus resultbekerja dengannya.
[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
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" 0hanyalah "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" 1untuk melipatgandakan semuanya 1.
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:
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.
sumber
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:
sumber
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
.sumber
Kode ini mengulangi empat elemen dalam array dan menambahkan hasil sebelumnya ke elemen saat ini:
sumber
Apa yang mereka katakan, tetapi perhatikan juga bahwa Anda tidak selalu perlu memberikan "nilai awal":
sama dengan
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.
sumber
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
sumber
Suntikan menerapkan blok
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.
sumber
tldr;
inject
berbeda darimap
dalam satu cara penting:inject
mengembalikan nilai eksekusi terakhir dari blok sedangkanmap
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:Efek yang sama tetapi
inject
lebih ringkas di sini.Anda akan sering menemukan tugas terjadi di
map
blok, sedangkan evaluasi terjadi diinject
blok.Metode mana yang Anda pilih tergantung pada ruang lingkup yang Anda inginkan
result
. Kapan tidak menggunakannya akan menjadi sesuatu seperti ini: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 harusresult
bekerja dengannya.sumber
setara dengan yang berikut:
sumber
[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.sumber
Kode ini tidak memungkinkan kemungkinan tidak melewati nilai awal, tetapi dapat membantu menjelaskan apa yang terjadi.
sumber
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?
Seperti apa awalnya?
Bisakah kita melakukan ini?
Apakah ini berhasil?
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
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
tetapi tidak ada yang kembali jadi ini hanya bertindak sama seperti sebelumnya
di blok elemen inspektur.
sumber
Ini adalah penjelasan yang sederhana dan cukup mudah dimengerti:
Lupakan "nilai awal" karena agak membingungkan di awal.
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: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
dan 10. "Nilai awal"
0
hanyalah "basis" untuk memulai. Dalam banyak kasus, Anda tidak membutuhkannya. Bayangkan jika Anda membutuhkan 1 * 2 * 3 * 4 dan itudan itu dilakukan. Anda tidak perlu "nilai awal"
1
untuk melipatgandakan semuanya1
.sumber
Ada bentuk lain dari metode .inject () Itu sangat membantu [4,5] .inject (&: +) Itu akan menjumlahkan semua elemen area
sumber
Hanya saja ,
reduce
ataufold
, jika Anda terbiasa dengan bahasa lain.sumber
Apakah sama dengan ini:
sumber