Katakanlah saya ingin menjumlahkan a.x
untuk setiap elemen di arr
.
arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return a.x + b.x})
>> NaN
Saya punya alasan untuk percaya bahwa kapak tidak ditentukan pada beberapa titik.
Berikut ini berfungsi dengan baik
arr = [1,2,4]
arr.reduce(function(a,b){return a + b})
>> 7
Apa yang saya lakukan salah dalam contoh pertama?
arr.reduce(function(a,b){return a + b})
dalam contoh kedua.Jawaban:
Setelah iterasi pertama Anda mengembalikan angka dan kemudian mencoba untuk mendapatkan properti
x
itu untuk ditambahkan ke objek berikutnya yang merupakanundefined
dan matematika yang melibatkanundefined
hasilNaN
.coba kembalikan objek berisi
x
properti dengan jumlah properti x dari parameter:Penjelasan ditambahkan dari komentar:
Nilai pengembalian setiap iterasi
[].reduce
digunakan sebagaia
variabel dalam iterasi berikutnya.Iterasi 1:
a = {x:1}
,b = {x:2}
,{x: 3}
ditugaskan untuka
di iterasi 2Iterasi 2:
a = {x:3}
,b = {x:4}
.Masalah dengan contoh Anda adalah bahwa Anda mengembalikan angka literal.
Iterasi 1:
a = {x:1}
,b = {x:2}
,// returns 3
sepertia
di iterasi berikutnyaIterasi 2:
a = 3
,b = {x:2}
kembaliNaN
Sejumlah literal
3
tidak (biasanya) memiliki properti yang dinamakanx
demikianundefined
danundefined + b.x
kembaliNaN
danNaN + <anything>
selaluNaN
Klarifikasi : Saya lebih suka metode saya daripada jawaban teratas lainnya di utas ini karena saya tidak setuju dengan gagasan bahwa melewatkan parameter opsional untuk dikurangi dengan angka ajaib untuk mengeluarkan angka primitif lebih bersih. Mungkin menghasilkan lebih sedikit baris yang ditulis tetapi jika itu kurang dibaca.
sumber
Cara yang lebih bersih untuk mencapai ini adalah dengan memberikan nilai awal:
Pertama kali fungsi anonim dipanggil, ia dipanggil dengan
(0, {x: 1})
dan kembali0 + 1 = 1
. Lain kali, ia dipanggil dengan(1, {x: 2})
dan kembali1 + 2 = 3
. Kemudian dipanggil dengan(3, {x: 4})
, akhirnya kembali7
.sumber
reduce
.TL; DR, tetapkan nilai awal
Menggunakan destrrukturisasi
arr.reduce( ( sum, { x } ) => sum + x , 0)
Tanpa merusak
arr.reduce( ( sum , cur ) => sum + cur.x , 0)
Dengan naskah
arr.reduce( ( sum, { x } : { x: number } ) => sum + x , 0)
Mari kita coba metode penghancuran:
Kunci untuk ini adalah menetapkan nilai awal. Nilai kembali menjadi parameter pertama dari iterasi berikutnya.
Teknik yang digunakan dalam jawaban atas tidak idiomatis
Jawaban yang diterima mengusulkan TIDAK melewati nilai "opsional". Ini salah, karena cara idiomatik adalah bahwa parameter kedua selalu disertakan. Mengapa? Tiga alasan:
1. Berbahaya - Tidak melewatkan nilai awal berbahaya dan dapat membuat efek samping dan mutasi jika fungsi panggilan balik ceroboh.
Melihat
Namun jika kita melakukannya dengan cara ini, dengan nilai awal:
Sebagai catatan, kecuali jika Anda bermaksud untuk bermutasi objek asli, atur parameter pertama
Object.assign
ke objek kosong. Seperti ini:Object.assign({}, a, b, c)
.2 - Inferensi Jenis Yang Lebih Baik - Saat menggunakan alat seperti Typecript atau editor seperti VS Code, Anda mendapatkan manfaat dari memberitahu kompiler awal dan dapat menangkap kesalahan jika Anda melakukannya dengan salah. Jika Anda tidak menetapkan nilai awal, dalam banyak situasi mungkin tidak dapat menebak dan Anda bisa berakhir dengan kesalahan runtime menyeramkan.
3 - Hormati Functors - JavaScript bersinar terbaik saat anak fungsional dalamnya dilepaskan. Dalam dunia fungsional, ada standar tentang bagaimana Anda "melipat" atau
reduce
array. Ketika Anda melipat atau menerapkan katamorfisme ke array, Anda mengambil nilai array itu untuk membangun tipe baru. Anda perlu mengkomunikasikan tipe yang dihasilkan - Anda harus melakukan ini bahkan jika tipe terakhir adalah nilai-nilai dalam array, array lain, atau jenis lainnya.Mari kita pikirkan dengan cara lain. Dalam JavaScript, fungsi dapat diedarkan seperti data, ini adalah cara kerja callback, apa hasil dari kode berikut?
[1,2,3].reduce(callback)
Apakah akan mengembalikan nomor? Sebuah Objek? Ini membuatnya lebih jelas
[1,2,3].reduce(callback,0)
Baca lebih lanjut tentang spesifikasi pemrograman fungsional di sini: https://github.com/fantasyland/fantasy-land#foldable
Lebih banyak latar belakang
The
reduce
Metode membutuhkan dua parameter,The
callback
fungsi mengambil parameter berikutUntuk iterasi pertama,
Jika
initialItem
disediakan,reduce
fungsi meneruskaninitialItem
sebagaiaccumulator
dan item pertama dari array sebagaiitemInArray
.Jika
initialItem
ini tidak disediakan,reduce
fungsi melewati item pertama dalam array sebagaiinitialItem
dan item kedua dalam array sebagaiitemInArray
yang dapat membingungkan perilaku.Saya mengajar dan merekomendasikan untuk selalu menetapkan nilai awal pengurangan.
Anda dapat melihat dokumentasi di:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Semoga ini membantu!
sumber
Orang lain telah menjawab pertanyaan ini, tetapi saya pikir saya akan menggunakan pendekatan lain. Daripada langsung menjumlahkan kapak, Anda dapat menggabungkan peta (dari kapak ke x) dan mengurangi (untuk menambahkan x's):
Memang, ini mungkin akan sedikit lebih lambat, tapi saya pikir itu layak disebut sebagai opsi.
sumber
Untuk memformalkan apa yang telah ditunjukkan, reducer adalah katamorphism yang mengambil dua argumen yang mungkin merupakan tipe yang sama secara kebetulan, dan mengembalikan tipe yang cocok dengan argumen pertama.
Itu berarti bahwa badan peredam harus tentang konversi
currentValue
dan nilai saat iniaccumulator
ke nilai baruaccumulator
.Ini bekerja dengan cara yang langsung, ketika menambahkan, karena akumulator dan nilai elemen keduanya bertipe sama (tetapi melayani tujuan yang berbeda).
Ini hanya berfungsi karena semuanya angka.
Sekarang kami memberikan nilai awal kepada agregator. Nilai awal harus menjadi tipe yang Anda harapkan sebagai agregator (tipe yang Anda harapkan sebagai nilai akhir), dalam sebagian besar kasus. Meskipun Anda tidak dipaksa untuk melakukan ini (dan tidak seharusnya), penting untuk diingat.
Setelah Anda tahu itu, Anda dapat menulis pengurangan yang berarti untuk masalah hubungan n: 1 lainnya.
Menghapus kata yang diulang:
Memberikan hitungan semua kata yang ditemukan:
Mengurangi array array, menjadi satu flat array:
Setiap kali Anda ingin beralih dari berbagai hal, ke nilai tunggal yang tidak cocok dengan 1: 1, pengurangan adalah sesuatu yang mungkin Anda pertimbangkan.
Faktanya, peta dan filter keduanya dapat diimplementasikan sebagai pengurangan:
Saya harap ini memberikan beberapa konteks lebih lanjut tentang cara menggunakan
reduce
.Satu tambahan untuk ini, yang belum saya bahas, adalah ketika ada harapan bahwa tipe input dan output secara khusus dimaksudkan untuk menjadi dinamis, karena elemen array adalah fungsi:
sumber
Untuk iterasi pertama 'a' akan menjadi objek pertama dalam array, maka ax + bx akan mengembalikan 1 + 2 yaitu 3. Sekarang di iterasi berikutnya, 3 dikembalikan ditugaskan ke, jadi a adalah nomor sekarang n memanggil kapak akan memberi NaN.
Solusi sederhana adalah pertama-tama memetakan angka dalam array dan kemudian menguranginya seperti di bawah ini:
di sini
arr.map(a=>a.x)
akan memberikan array angka [1,2,4] sekarang menggunakan.reduce(function(a,b){return a+b})
akan dengan mudah menambahkan angka-angka ini tanpa hasselSolusi sederhana lainnya adalah dengan memberikan jumlah awal sebagai nol dengan menetapkan 0 ke 'a' seperti di bawah ini:
sumber
Pada setiap langkah pengurangan Anda, Anda tidak mengembalikan
{x:???}
objek baru . Jadi, Anda juga perlu melakukan:atau yang perlu Anda lakukan
sumber
Pada langkah pertama, itu akan berfungsi dengan baik karena nilai
a
akan 1 dan bahwab
akan 2 tetapi karena 2 + 1 akan dikembalikan dan pada langkah berikutnya nilaib
akan menjadi nilai balikfrom step 1 i.e 3
dan dengan demikianb.x
akan tidak terdefinisi .. .dan undefined + anyNumber akan menjadi NaN dan itulah mengapa Anda mendapatkan hasil itu.Sebagai gantinya Anda dapat mencoba ini dengan memberikan nilai awal sebagai nol yaitu
sumber
Jika Anda memiliki objek yang kompleks dengan banyak data, seperti array objek, Anda dapat mengambil pendekatan langkah demi langkah untuk menyelesaikannya.
Untuk misalnya:
Pertama, Anda harus memetakan array Anda ke array baru yang Anda minati, bisa berupa array nilai baru dalam contoh ini.
Fungsi panggilan balik ini akan mengembalikan array baru yang hanya berisi nilai-nilai dari array asli dan menyimpannya pada nilai const. Sekarang const nilai Anda adalah array seperti ini:
Dan sekarang Anda siap melakukan pengurangan Anda:
Seperti yang Anda lihat, metode pengurangan menjalankan fungsi panggilan balik beberapa kali. Untuk setiap waktu, dibutuhkan nilai item saat ini dalam array dan jumlah dengan akumulator. Jadi untuk menjumlahkannya dengan benar, Anda perlu mengatur nilai awal akumulator Anda sebagai argumen kedua dari metode pengurangan.
Sekarang Anda memiliki const sum baru Anda dengan nilai 30.
sumber
mengurangi fungsi yang berulang pada koleksi
diterjemahkan menjadi:
Untuk memahami seluk-beluk fungsi "perkecil", saya sarankan Anda melihat kode sumber fungsi ini. Pustaka Lodash memiliki fungsi pengurangan yang bekerja persis sama dengan fungsi "perkecil" di ES6.
Inilah tautannya: kurangi kode sumber
sumber
untuk mengembalikan jumlah semua
x
alat peraga:sumber
Anda bisa menggunakan peta dan mengurangi fungsi
sumber
Array mengurangi fungsi mengambil tiga parameter yaitu, initialValue (default 0), akumulator dan nilai saat ini. Secara default nilai initialValue akan menjadi "0". yang diambil oleh akumulator
Mari kita lihat ini dalam kode.
Sekarang contoh yang sama dengan Nilai awal:
Hal yang sama berlaku untuk array objek juga (pertanyaan stackoverflow saat ini):
SATU HAL YANG DIPEROLEH DALAM MIND adalah InitialValue secara default adalah 0 dan dapat diberikan apa pun yang saya maksud {}, [] dan angka
sumber
sumber
Anda tidak boleh menggunakan kapak untuk akumulator, Alih-alih Anda dapat melakukan seperti ini `arr = [{x: 1}, {x: 2}, {x: 4}]
arr.reduce (fungsi (a, b) {a + bx}, 0) `
sumber