Apa metode terbaik atau paling ringkas untuk mengembalikan string yang diulang dalam jumlah yang sewenang-wenang?
Berikut ini adalah bidikan terbaik saya sejauh ini:
function repeat(s, n){
var a = [];
while(a.length < n){
a.push(s);
}
return a.join('');
}
javascript
string
brad
sumber
sumber
Jawaban:
Saya akan menempatkan fungsi ini ke objek String secara langsung. Alih-alih membuat array, mengisinya, dan bergabung dengan char kosong, buat saja array dengan panjang yang sesuai, dan bergabunglah dengan string yang Anda inginkan. Hasil yang sama, lebih sedikit proses!
sumber
String.repeat = function(string, num){ return new Array(parseInt(num) + 1).join(string); };
. Sebut saja seperti ini:String.repeat('/\', 20)
Saya telah menguji kinerja semua pendekatan yang diusulkan.
Inilah varian tercepat yang saya miliki.
Atau sebagai fungsi yang berdiri sendiri :
Ini didasarkan pada algoritma artistoex . Ini sangat cepat. Dan semakin besar
count
, semakin cepat dibandingkan dengannew Array(count + 1).join(string)
pendekatan tradisional .Saya hanya mengubah 2 hal:
pattern = this
denganpattern = this.valueOf()
(menghapus satu konversi jenis yang jelas);if (count < 1)
pemeriksaan dari prototypejs ke bagian atas fungsi untuk mengecualikan tindakan yang tidak perlu dalam kasus itu.UPD
Menciptakan taman bermain pengujian kecil di sini untuk mereka yang tertarik.
variabel
count
~ 0 .. 100:konstan
count
= 1024:Gunakan dan buat lebih cepat jika bisa :)
sumber
count < 1
kasus ini optimasi yang benar-benar tidak perlu.Masalah ini adalah masalah optimisasi JavaScript yang terkenal / "klasik", disebabkan oleh fakta bahwa string JavaScript "tidak dapat diubah" dan penambahan dengan penggabungan bahkan satu karakter ke string memerlukan kreasi, termasuk alokasi memori untuk dan penyalinan ke , seluruh string baru.
Sayangnya, jawaban yang diterima pada halaman ini salah, di mana "salah" berarti oleh faktor kinerja 3x untuk string satu karakter sederhana, dan 8x-97x untuk string pendek yang diulang lebih sering, hingga 300x untuk kalimat berulang, dan jauh salah ketika mengambil batas rasio kompleksitas algoritma
n
hingga tak terhingga. Juga, ada jawaban lain di halaman ini yang hampir benar (berdasarkan salah satu dari banyak generasi dan variasi solusi yang tepat yang beredar di seluruh Internet dalam 13 tahun terakhir). Namun, solusi "hampir tepat" ini melewatkan titik kunci dari algoritma yang benar yang menyebabkan penurunan kinerja 50%.Hasil Kinerja JS untuk jawaban yang diterima, jawaban lain dengan performa terbaik (berdasarkan versi terdegradasi dari algoritma asli dalam jawaban ini), dan jawaban ini menggunakan algoritme saya yang dibuat 13 tahun yang lalu
~ Oktober 2000 Saya menerbitkan algoritma untuk masalah yang tepat ini yang secara luas diadaptasi, dimodifikasi, kemudian akhirnya kurang dipahami dan dilupakan. Untuk mengatasi masalah ini, pada bulan Agustus 2008 saya menerbitkan sebuah artikel http://www.webreference.com/programming/javascript/jkm3/3.html menjelaskan algoritma dan menggunakannya sebagai contoh sederhana pengoptimalan tujuan umum JavaScript. Sekarang, Referensi Web telah menggosok informasi kontak saya dan bahkan nama saya dari artikel ini. Dan sekali lagi, algoritme telah banyak diadaptasi, dimodifikasi, kemudian kurang dipahami dan sebagian besar dilupakan.
Dalam waktu dua bulan setelah publikasi artikel itu, pertanyaan yang sama ini diposting ke Stack Overflow dan terbang di bawah radar saya sampai sekarang, ketika tampaknya algoritma asli untuk masalah ini sekali lagi dilupakan. Solusi terbaik yang tersedia di halaman Stack Overflow ini adalah versi modifikasi dari solusi saya, mungkin dipisahkan oleh beberapa generasi. Sayangnya, modifikasi merusak optimalitas solusi. Bahkan, dengan mengubah struktur loop dari yang asli, solusi yang dimodifikasi melakukan langkah ekstra yang sama sekali tidak diperlukan dari duplikasi eksponensial (sehingga bergabung dengan string terbesar yang digunakan dalam jawaban yang tepat dengan dirinya sendiri waktu tambahan dan kemudian membuangnya).
Di bawah ini terjadi diskusi tentang beberapa optimasi JavaScript yang terkait dengan semua jawaban untuk masalah ini dan untuk kepentingan semua.
Teknik: Hindari referensi ke objek atau properti objek
Untuk menggambarkan bagaimana teknik ini bekerja, kami menggunakan fungsi JavaScript kehidupan nyata yang menciptakan string dengan panjang berapa pun yang dibutuhkan. Dan seperti yang akan kita lihat, lebih banyak optimasi dapat ditambahkan!
Fungsi seperti yang digunakan di sini adalah membuat padding untuk meluruskan kolom teks, untuk memformat uang, atau untuk mengisi data blok hingga batas. Fungsi pembuatan teks juga memungkinkan input panjang variabel untuk menguji fungsi lain yang beroperasi pada teks. Fungsi ini adalah salah satu komponen penting dari modul pemrosesan teks JavaScript.
Saat kami melanjutkan, kami akan membahas dua teknik optimasi yang paling penting sambil mengembangkan kode asli menjadi algoritma yang dioptimalkan untuk membuat string. Hasil akhirnya adalah kekuatan industri, fungsi kinerja tinggi yang saya gunakan di mana-mana - menyelaraskan harga barang dan total dalam formulir pemesanan JavaScript, pemformatan data, dan pemformatan pesan email / teks dan banyak kegunaan lainnya.
Kode asli untuk membuat string
stringFill1()
Sintaksnya di sini jelas. Seperti yang Anda lihat, kami telah menggunakan variabel fungsi lokal, sebelum melanjutkan ke optimasi lainnya.
Perlu diketahui bahwa ada satu referensi tidak bersalah ke properti objek
s.length
dalam kode yang merusak kinerjanya. Lebih buruk lagi, penggunaan properti objek ini mengurangi kesederhanaan program dengan membuat asumsi bahwa pembaca tahu tentang properti objek string JavaScript.Penggunaan properti objek ini merusak keumuman program komputer. Program mengasumsikan bahwa
x
harus berupa string yang panjang. Ini membatasi penerapanstringFill1()
fungsi hanya untuk pengulangan karakter tunggal. Bahkan karakter tunggal tidak dapat digunakan jika mengandung banyak byte seperti entitas HTML
.Masalah terburuk yang disebabkan oleh penggunaan properti objek yang tidak perlu ini adalah bahwa fungsi tersebut menciptakan loop tak terbatas jika diuji pada string input kosong
x
. Untuk memeriksa sifat umum, terapkan suatu program dengan jumlah input sekecil mungkin. Suatu program yang mogok ketika diminta untuk melebihi jumlah memori yang tersedia memiliki alasan. Program seperti ini yang macet saat diminta tidak menghasilkan apa-apa tidak dapat diterima. Terkadang kode cantik adalah kode beracun.Kesederhanaan mungkin merupakan tujuan ganda dari pemrograman komputer, tetapi umumnya tidak. Ketika suatu program tidak memiliki tingkat umum yang masuk akal, itu tidak sah untuk mengatakan, "Program ini cukup baik sejauh itu berjalan." Seperti yang Anda lihat, menggunakan
string.length
properti mencegah program ini bekerja dalam pengaturan umum, dan pada kenyataannya, program yang salah siap menyebabkan peramban atau kerusakan sistem.Apakah ada cara untuk meningkatkan kinerja JavaScript ini serta merawat dua masalah serius ini?
Tentu saja. Cukup gunakan bilangan bulat.
Kode yang dioptimalkan untuk membuat string
stringFill2()
Kode waktu untuk membandingkan
stringFill1()
danstringFill2()
Keberhasilan sejauh ini
stringFill2()
stringFill1()
membutuhkan 47.297 mikrodetik (sepersejuta detik) untuk mengisi string 100-byte, danstringFill2()
membutuhkan 27,68 mikrodetik untuk melakukan hal yang sama. Itu hampir dua kali lipat dalam kinerja dengan menghindari referensi ke properti objek.Teknik: Hindari menambahkan string pendek ke string panjang
Hasil kami sebelumnya terlihat bagus - sangat bagus, sebenarnya. Fungsi yang ditingkatkan
stringFill2()
jauh lebih cepat karena penggunaan dua optimasi pertama kami. Percayakah Anda jika saya memberi tahu Anda bahwa itu dapat ditingkatkan menjadi jauh lebih cepat daripada sekarang?Ya, kita dapat mencapai tujuan itu. Saat ini kita perlu menjelaskan bagaimana kita menghindari menambahkan string pendek ke string panjang.
Perilaku jangka pendek tampaknya cukup baik, dibandingkan dengan fungsi asli kami. Ilmuwan komputer suka menganalisis "perilaku asimptotik" dari suatu fungsi atau algoritma program komputer, yang berarti mempelajari perilaku jangka panjangnya dengan mengujinya dengan input yang lebih besar. Terkadang tanpa melakukan tes lebih lanjut, seseorang tidak pernah menyadari cara-cara program komputer dapat ditingkatkan. Untuk melihat apa yang akan terjadi, kita akan membuat string 200-byte.
Masalah yang muncul dengan
stringFill2()
Menggunakan fungsi timing kami, kami menemukan bahwa waktu meningkat menjadi 62,54 mikrodetik untuk string 200-byte, dibandingkan dengan 27,68 untuk string 100-byte. Sepertinya waktunya harus dua kali lipat untuk melakukan pekerjaan dua kali lebih banyak, tetapi justru berlipat tiga atau empat kali lipat. Dari pengalaman pemrograman, hasil ini tampak aneh, karena jika ada, fungsi harus sedikit lebih cepat karena pekerjaan dilakukan lebih efisien (200 byte per panggilan fungsi daripada 100 byte per panggilan fungsi). Masalah ini berkaitan dengan properti berbahaya dari string JavaScript: String JavaScript "tidak dapat diubah."
Abadi berarti Anda tidak dapat mengubah string setelah itu dibuat. Dengan menambahkan satu byte pada satu waktu, kami tidak menggunakan upaya satu byte lagi. Kami benar-benar menciptakan kembali seluruh string ditambah satu byte lagi.
Efeknya, untuk menambahkan satu byte lagi ke string 100-byte, dibutuhkan kerja senilai 101 byte. Mari kita secara singkat menganalisis biaya komputasi untuk membuat serangkaian
N
byte. Biaya penambahan byte pertama adalah 1 unit upaya komputasi. Biaya menambahkan byte kedua bukan satu unit tetapi 2 unit (menyalin byte pertama ke objek string baru serta menambahkan byte kedua). Bita ketiga membutuhkan biaya 3 unit, dll.C(N) = 1 + 2 + 3 + ... + N = N(N+1)/2 = O(N^2)
. SimbolO(N^2)
diucapkan Big O dari N kuadrat, dan itu berarti bahwa biaya komputasi dalam jangka panjang sebanding dengan kuadrat dari panjang string. Untuk membuat 100 karakter dibutuhkan 10.000 unit kerja, dan untuk membuat 200 karakter dibutuhkan 40.000 unit kerja.Inilah sebabnya mengapa dibutuhkan lebih dari dua kali lebih lama untuk membuat 200 karakter dari 100 karakter. Padahal, seharusnya memakan waktu empat kali lebih lama. Pengalaman pemrograman kami benar karena pekerjaan dilakukan sedikit lebih efisien untuk string yang lebih lama, dan karenanya hanya butuh sekitar tiga kali lebih lama. Setelah overhead panggilan fungsi diabaikan untuk berapa lama string yang kita buat, sebenarnya akan membutuhkan waktu empat kali lebih banyak untuk membuat string dua kali lebih lama.
(Catatan historis: Analisis ini tidak selalu berlaku untuk string dalam kode sumber, seperti
html = 'abcd\n' + 'efgh\n' + ... + 'xyz.\n'
, karena kompiler kode sumber JavaScript dapat menggabungkan string sebelum menjadikannya menjadi objek string JavaScript. Hanya beberapa tahun yang lalu, implementasi KJS dari JavaScript akan membeku atau mogok saat memuat string panjang kode sumber yang bergabung dengan tanda plus. Karena waktu komputasiO(N^2)
itu tidak sulit untuk membuat halaman Web yang membebani browser Web Konqueror atau Safari, yang menggunakan inti mesin KJS JavaScript. Saya pertama kali menemukan masalah ini ketika saya sedang mengembangkan bahasa markup dan parser bahasa markup JavaScript, dan kemudian saya menemukan apa yang menyebabkan masalah ketika saya menulis skrip saya untuk Termasuk JavaScript.)Jelas penurunan kinerja yang cepat ini adalah masalah besar. Bagaimana kita bisa menghadapinya, mengingat kita tidak bisa mengubah cara JavaScript menangani string sebagai objek yang tidak dapat diubah? Solusinya adalah dengan menggunakan algoritma yang menciptakan string sesering mungkin.
Untuk memperjelas, tujuan kami adalah untuk menghindari menambahkan string pendek ke string panjang, karena untuk menambahkan string pendek, seluruh string panjang juga harus diduplikasi.
Bagaimana algoritma bekerja untuk menghindari penambahan string pendek ke string panjang
Berikut adalah cara yang baik untuk mengurangi berapa kali objek string baru dibuat. Menggabungkan panjang string yang lebih panjang sehingga lebih dari satu byte pada suatu waktu ditambahkan ke output.
Misalnya, untuk membuat string panjang
N = 9
:Melakukan ini diperlukan membuat string dengan panjang 1, membuat string dengan panjang 2, membuat string dengan panjang 4, membuat string dengan panjang 8, dan akhirnya, membuat string dengan panjang 9. Berapa biaya yang telah kita hemat?
Biaya lama
C(9) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 9 = 45
.Biaya baru
C(9) = 1 + 2 + 4 + 8 + 9 = 24
.Perhatikan bahwa kita harus menambahkan string dengan panjang 1 ke string dengan panjang 0, kemudian string dengan panjang 1 ke string dengan panjang 1, kemudian string dengan panjang 2 ke string dengan panjang 2, kemudian string dengan panjang 4 ke string dengan panjang 4, lalu string dengan panjang 8 ke string dengan panjang 1, untuk mendapatkan string dengan panjang 9. Apa yang kita lakukan dapat diringkas sebagai menghindari menambahkan string pendek ke string panjang, atau di lain kata-kata, mencoba menyatukan string yang panjangnya sama atau hampir sama.
Untuk biaya komputasi lama kami menemukan rumus
N(N+1)/2
. Apakah ada formula untuk biaya baru? Ya, tapi rumit. Yang penting adalah ituO(N)
, dan menggandakan panjang tali akan kira-kira dua kali lipat jumlah pekerjaan daripada empat kali lipatnya.Kode yang mengimplementasikan ide baru ini hampir sama rumitnya dengan rumus untuk biaya komputasi. Ketika Anda membacanya, ingat itu
>>= 1
artinya bergeser ke kanan sebesar 1 byte. Jadi jikan = 10011
angka biner, makan >>= 1
menghasilkan nilain = 1001
.Bagian lain dari kode yang mungkin tidak Anda kenali adalah bitwise dan operator, ditulis
&
. Ekspresin & 1
bernilai true jika digit biner terakhirn
adalah 1, dan false jika digit biner terakhirn
adalah 0.stringFill3()
Fungsi baru yang sangat efisienItu terlihat jelek bagi mata yang tidak terlatih, tetapi kinerjanya tidak kalah indah.
Mari kita lihat seberapa baik fungsi ini bekerja. Setelah melihat hasilnya, kemungkinan Anda tidak akan pernah melupakan perbedaan antara suatu
O(N^2)
algoritma danO(N)
algoritma.stringFill1()
membutuhkan 88,7 mikrodetik (sepersejuta detik) untuk membuat string 200-byte,stringFill2()
membutuhkan 62,54, danstringFill3()
hanya membutuhkan 4,608. Apa yang membuat algoritma ini jauh lebih baik? Semua fungsi mengambil keuntungan dari menggunakan variabel fungsi lokal, tetapi mengambil keuntungan dari teknik optimasi kedua dan ketiga menambahkan peningkatan dua kali lipat untuk kinerjastringFill3()
.Analisis yang lebih dalam
Apa yang membuat fungsi khusus ini membuat kompetisi keluar dari air?
Seperti yang saya sebutkan, alasan kedua fungsi ini,
stringFill1()
danstringFill2()
, berjalan sangat lambat adalah bahwa string JavaScript tidak dapat diubah. Memori tidak dapat dialokasikan kembali untuk memungkinkan satu byte lagi pada satu waktu ditambahkan ke data string yang disimpan oleh JavaScript. Setiap kali satu byte lagi ditambahkan ke ujung string, seluruh string dibuat ulang dari awal hingga akhir.Dengan demikian, untuk meningkatkan kinerja skrip, kita harus melakukan pra-string string yang lebih panjang dengan menggabungkan dua string bersama sebelumnya, dan kemudian secara rekursif membangun panjang string yang diinginkan.
Misalnya, untuk membuat string byte 16 huruf, pertama string dua byte akan dikomputasi. Kemudian string dua byte akan digunakan kembali untuk precompute string empat byte. Kemudian string empat byte akan digunakan kembali untuk precompute string delapan byte. Akhirnya, dua string delapan byte akan digunakan kembali untuk membuat string baru yang diinginkan sebesar 16 byte. Secara keseluruhan empat string baru harus dibuat, satu panjang 2, satu panjang 4, satu panjang 8 dan satu panjang 16. Total biaya adalah 2 + 4 + 8 + 16 = 30.
Dalam jangka panjang efisiensi ini dapat dihitung dengan menambahkan urutan terbalik dan menggunakan deret geometri yang dimulai dengan suku pertama a1 = N dan memiliki rasio umum r = 1/2. Jumlah deret geometri diberikan oleh
a_1 / (1-r) = 2N
.Ini lebih efisien daripada menambahkan satu karakter untuk membuat string baru dengan panjang 2, membuat string baru dengan panjang 3, 4, 5, dan seterusnya, sampai 16. Algoritma sebelumnya menggunakan proses penambahan byte tunggal pada suatu waktu , dan total biaya itu akan menjadi
n (n + 1) / 2 = 16 (17) / 2 = 8 (17) = 136
.Jelas, 136 adalah angka yang jauh lebih besar dari 30, dan algoritma sebelumnya membutuhkan lebih banyak waktu untuk membangun string.
Untuk membandingkan dua metode, Anda dapat melihat seberapa cepat algoritma rekursif (juga disebut "divide and conquer") ada pada string dengan panjang 123.457. Pada komputer FreeBSD saya, algoritma ini, diimplementasikan dalam
stringFill3()
fungsi, membuat string dalam 0,001058 detik, sedangkanstringFill1()
fungsi asli membuat string dalam 0,0808 detik. Fungsi baru 76 kali lebih cepat.Perbedaan kinerja tumbuh seiring panjangnya string menjadi lebih besar. Dalam batas sebagai string yang lebih besar dan lebih besar dibuat, fungsi asli berperilaku kira-kira seperti waktu
C1
(konstan)N^2
, dan fungsi baru berperilaku seperti waktuC2
(konstan)N
.Dari percobaan kami, kami dapat menentukan nilai
C1
menjadiC1 = 0.0808 / (123457)2 = .00000000000530126997
, dan nilaiC2
menjadiC2 = 0.001058 / 123457 = .00000000856978543136
. Dalam 10 detik, fungsi baru dapat membuat string berisi 1.166.890.359 karakter. Untuk membuat string yang sama ini, fungsi lama akan membutuhkan waktu 7.218.384 detik.Ini hampir tiga bulan dibandingkan dengan sepuluh detik!
Saya hanya menjawab (beberapa tahun terlambat) karena solusi asli saya untuk masalah ini telah beredar di Internet selama lebih dari 10 tahun, dan tampaknya masih kurang dipahami oleh beberapa orang yang mengingatnya. Saya berpikir bahwa dengan menulis artikel tentang itu di sini saya akan membantu:
Optimalisasi Kinerja untuk JavaScript Kecepatan Tinggi / Halaman 3
Sayangnya, beberapa solusi lain yang disajikan di sini masih beberapa yang membutuhkan waktu tiga bulan untuk menghasilkan jumlah output yang sama dengan yang dihasilkan oleh solusi yang tepat dalam 10 detik.
Saya ingin meluangkan waktu untuk mereproduksi bagian dari artikel di sini sebagai jawaban kanonik pada Stack Overflow.
Perhatikan bahwa algoritma berkinerja terbaik di sini jelas berdasarkan pada algoritme saya dan mungkin diturunkan dari adaptasi generasi ke-3 atau ke-4 orang lain. Sayangnya, modifikasi mengakibatkan pengurangan kinerjanya. Variasi solusi saya yang disajikan di sini mungkin tidak mengerti
for (;;)
ekspresi membingungkan saya yang terlihat seperti loop tak terbatas utama dari server yang ditulis dalam C, dan yang hanya dirancang untuk memungkinkan pernyataan break diposisikan dengan hati-hati untuk kontrol loop, cara paling ringkas untuk hindari mereplikasi string secara eksponensial satu waktu ekstra yang tidak perlu.sumber
Yang ini cukup efisien
sumber
Kabar baik!
String.prototype.repeat
adalah sekarang menjadi bagian dari JavaScript .Metode ini didukung oleh semua browser utama, kecuali Internet Explorer dan Android Webview. Untuk daftar terbaru, lihat MDN: String.prototype.repeat> Kompatibilitas browser .
MDN memiliki polyfill untuk browser tanpa dukungan.
sumber
String.prototype.repeat sekarang Standar ES6.
sumber
Memperluas solusi P. Bailey :
Dengan cara ini Anda harus aman dari tipe argumen yang tidak terduga:
EDIT: Kredit untuk melakukan jerone untuk
++num
idenya yang elegan !sumber
String.prototype.repeat = function(n){return new Array(isNaN(n) ? 1 : ++n).join(this);}
Menggunakan
Array(N+1).join("string_to_repeat")
sumber
ini adalah cara mengulangi string beberapa kali menggunakan delimeter.
sumber
Berikut ini adalah peningkatan 5-7% pada jawaban disfated
Buka gulungannya dengan berhenti
count > 1
dan lakukanresult += pattnern
konser tambahan setelah putaran itu. Ini akan menghindari putaran final yang sebelumnya tidak digunakanpattern += pattern
tanpa harus menggunakan if-check mahal. Hasil akhirnya akan terlihat seperti ini:Dan ini biola disfated yang bercabang untuk versi yang belum dibuka: http://jsfiddle.net/wsdfg/
sumber
sumber
var r=s; for (var a=1;...
:)))) Bagaimanapun menurut tes ini ( jsperf.com/string-repeat/2 ) melakukan loop sederhana dengan rangkaian string seperti apa yang Anda sarankan tampaknya jauh lebih cepat di Chrome dibandingkan menggunakan Array .Ikuti.Pengujian berbagai metode:
sumber
Ini versi aman JSLint
sumber
Untuk semua browser
Ini tentang singkat seperti yang didapat:
Jika Anda juga peduli dengan kinerja, ini adalah pendekatan yang jauh lebih baik:
Jika Anda ingin membandingkan kinerja kedua opsi, lihat Fiddle dan Fiddle ini untuk tes benchmark. Selama pengujian saya sendiri, opsi kedua adalah sekitar 2 kali lebih cepat di Firefox dan sekitar 4 kali lebih cepat di Chrome!
Hanya untuk peramban modern:
Di browser modern, kini Anda juga dapat melakukan ini:
Opsi ini tidak hanya lebih pendek dari kedua opsi lainnya, tetapi bahkan lebih cepat dari opsi kedua.
Sayangnya, itu tidak berfungsi di versi Internet Explorer apa pun. Angka-angka dalam tabel menentukan versi browser pertama yang sepenuhnya mendukung metode ini:
sumber
Anda bisa mengujinya di JSFiddle . Dipatuhi tolak pada hacky
Array.join
dan milik saya, secara kasar, 10 (Chrome) hingga 100 (Safari) hingga 200 (Firefox) kali lebih cepat (tergantung pada browser).sumber
Hanya fungsi pengulangan lainnya:
sumber
ES2015
telah menyadarirepeat()
metode ini !http://www.ecma-international.org/ecma-262/6.0/#sec-string.prototype.repeat
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ String / ulangi
http://www.w3schools.com/jsref/jsref_repeat.asp
sumber
Ini mungkin yang rekursif terkecil: -
sumber
Fiddle: http://jsfiddle.net/3Y9v2/
sumber
Rangkaian rekursif sederhana
Saya hanya ingin mencobanya, dan membuat ini:
Saya tidak bisa mengatakan saya terlalu memikirkannya, dan mungkin menunjukkan :-)
Ini bisa dibilang lebih baik
Dan ini sangat mirip dengan jawaban yang sudah diposting - Saya tahu ini.
Tetapi mengapa harus rekursif sama sekali?
Dan bagaimana dengan perilaku standar kecil juga?
Karena , meskipun metode non rekursif akan menangani pengulangan besar secara sewenang-wenang tanpa mencapai batas tumpukan panggilan, itu jauh lebih lambat.
Mengapa saya repot-repot menambahkan lebih banyak metode yang tidak sepintar itu yang sudah diposting?
Sebagian untuk hiburan saya sendiri, dan sebagian untuk menunjukkan dengan cara paling sederhana saya tahu bahwa ada banyak cara untuk menguliti kucing, dan tergantung pada situasinya, sangat mungkin bahwa metode yang tampaknya terbaik tidak ideal.
Metode yang relatif cepat dan canggih secara efektif bisa crash dan terbakar dalam keadaan tertentu, sementara metode yang lebih lambat, lebih sederhana dapat menyelesaikan pekerjaan - pada akhirnya.
Beberapa metode mungkin sedikit lebih dari eksploitasi, dan karena itu cenderung ada tetap luar keberadaan, dan metode lain dapat bekerja dengan indah dalam semua kondisi, tetapi begitu dibangun sehingga orang hanya tidak tahu cara kerjanya.
"Jadi bagaimana jika aku tidak tahu cara kerjanya ?!"
Serius?
JavaScript menderita salah satu kekuatan terbesarnya; itu sangat toleran terhadap perilaku buruk, dan sangat fleksibel sehingga akan membungkuk ke belakang untuk mengembalikan hasil, ketika itu mungkin lebih baik untuk semua orang jika itu patah!
"Dengan kekuatan besar, datang tanggung jawab besar" ;-)
Tetapi yang lebih serius dan penting, meskipun pertanyaan umum seperti ini memang mengarah pada kehebatan dalam bentuk jawaban cerdas bahwa jika tidak ada yang lain, perluas pengetahuan dan wawasan Anda, pada akhirnya, tugas yang ada - skrip praktis yang menggunakan metode yang dihasilkan - mungkin membutuhkan sedikit lebih sedikit, atau sedikit lebih pintar dari yang disarankan.
Ini "sempurna" algoritma yang menyenangkan dan semua, tapi "satu ukuran cocok untuk semua" akan jarang jika pernah lebih baik dari tailor made.
Khotbah ini disampaikan kepada Anda karena kurang tidur dan minat yang lewat. Majulah dan kode!
sumber
Pertama, pertanyaan OP tampaknya tentang keringkasan - yang saya pahami berarti "sederhana dan mudah dibaca", sementara sebagian besar jawaban tampaknya tentang efisiensi - yang jelas bukan hal yang sama dan saya juga berpikir bahwa kecuali Anda menerapkan beberapa khusus algoritma manipulasi data besar, tidak perlu khawatir Anda ketika Anda datang untuk mengimplementasikan fungsi Javascript manipulasi data dasar. Keringkasan jauh lebih penting.
Kedua, seperti yang dicatat André Laszlo, String.repeat adalah bagian dari ECMAScript 6 dan sudah tersedia di beberapa implementasi populer - jadi implementasi yang paling ringkas
String.repeat
adalah bukan untuk mengimplementasikannya ;-)Terakhir, jika Anda perlu mendukung host yang tidak menawarkan implementasi ECMAScript 6, polyfill MDN yang disebutkan oleh André Laszlo sama sekali tidak ringkas.
Jadi, tanpa basa-basi lagi - inilah polyfill ringkas saya :
Ya, ini adalah rekursi. Saya suka rekursi - rekursi sederhana dan jika dilakukan dengan benar mudah dimengerti. Mengenai efisiensi, jika bahasa mendukungnya mereka bisa sangat efisien jika ditulis dengan benar.
Dari tes saya, metode ini ~ 60% lebih cepat dari
Array.join
pendekatan. Meskipun jelas-jelas tidak ada implementasi disfated dekat, itu jauh lebih sederhana daripada keduanya.Setup pengujian saya adalah simpul v0.10, menggunakan "mode Ketat" (Saya pikir ini memungkinkan semacam TCO ), memanggil
repeat(1000)
string 10 karakter sejuta kali.sumber
Jika Anda menganggap semua definisi prototipe, kreasi array, dan operasi gabungan ini berlebihan, cukup gunakan kode baris tunggal di mana Anda memerlukannya. String S berulang N kali:
sumber
Array(N + 1).join(str)
metode ini jika itu bukan hambatan kinerja). Jika ada kesempatan sekecil apa pun Anda akan menggunakannya dua kali, pindahkan ke fungsi yang sesuai namanya.Gunakan Lodash untuk fungsionalitas utilitas Javascript, seperti string berulang.
Lodash memberikan kinerja yang bagus dan kompatibilitas ECMAScript.
Saya sangat merekomendasikannya untuk pengembangan UI dan juga berfungsi dengan baik di sisi server.
Inilah cara mengulangi string "yo" 2 kali menggunakan Lodash:
sumber
Solusi rekursif menggunakan membagi dan menaklukkan:
sumber
Saya datang ke sini secara acak dan tidak pernah punya alasan untuk mengulangi char di javascript sebelumnya.
Saya terkesan dengan cara artistoex melakukannya dan hasil yang dihina. Saya perhatikan bahwa senar string terakhir tidak perlu, seperti Dennis juga tunjukkan.
Saya memperhatikan beberapa hal lagi ketika bermain dengan sampling disfated disatukan.
Hasilnya bervariasi dalam jumlah yang cukup sering menguntungkan untuk yang terakhir berjalan dan algoritma yang sama sering joki untuk posisi. Salah satu hal yang saya ubah adalah alih-alih menggunakan jumlah yang dihasilkan JSLitmus sebagai benih untuk panggilan; karena hitungan dihasilkan berbeda untuk berbagai metode, saya memasukkan indeks. Ini membuat benda itu jauh lebih dapat diandalkan. Saya kemudian melihat untuk memastikan bahwa berbagai ukuran string diteruskan ke fungsi. Ini mencegah beberapa variasi yang saya lihat, di mana beberapa algoritma melakukan lebih baik pada karakter tunggal atau string yang lebih kecil. Namun 3 metode teratas semuanya bekerja dengan baik terlepas dari ukuran string.
Set uji bercabang
http://jsfiddle.net/schmide/fCqp3/134/
Saya kemudian memasukkan perbaikan Dennis dan memutuskan untuk melihat apakah saya bisa menemukan cara untuk sedikit lebih banyak.
Karena javascript tidak dapat mengoptimalkan hal-hal, cara terbaik untuk meningkatkan kinerja adalah dengan menghindari hal-hal secara manual. Jika saya mengambil 4 hasil pertama yang sepele dari loop, saya bisa menghindari 2-4 toko string dan menulis toko akhir langsung ke hasilnya.
Ini menghasilkan peningkatan 1-2% rata-rata di atas perbaikan Dennis. Namun, proses yang berbeda dan browser yang berbeda akan menunjukkan varian yang cukup adil sehingga kode tambahan ini mungkin tidak sepadan dengan usaha dari 2 algoritma sebelumnya.
Sebuah Grafik
Sunting: Saya melakukan ini sebagian besar di bawah chrome. Firefox dan IE akan sering menguntungkan Dennis beberapa%.
sumber
Metode sederhana:
sumber
Orang terlalu rumit ini sampai pada tingkat yang konyol atau menyia-nyiakan kinerja. Array? Pengulangan? Anda pasti bercanda.
Edit. Saya menjalankan beberapa tes sederhana untuk membandingkan dengan versi bitwise yang diposting oleh artistoex / disfated dan sekelompok orang lain. Yang terakhir hanya sedikit lebih cepat, tetapi urutan besarnya lebih hemat memori. Untuk 10.00000 pengulangan kata 'blah', proses Node naik menjadi 46 megabita dengan algoritma penyatuan sederhana (di atas), tetapi hanya 5,5 megabita dengan algoritma logaritmik. Yang terakhir jelas cara untuk pergi. Pengeposan ulang demi kejelasan:
sumber
string += string
separuh waktu yang berlebihan .String penggabungan berdasarkan pada angka.
Semoga itu bisa membantu!
sumber
Dengan ES8 Anda juga dapat menggunakan
padStart
ataupadEnd
untuk ini. misalnya.sumber