Bagaimana cara memutus loop?
var largest=0
for(i<-999 to 1 by -1) {
for (j<-i to 1 by -1) {
val product=i*j
if (largest>product)
// I want to break out here
else
if(product.toString.equals(product.toString.reverse))
largest=largest max product
}
}
Bagaimana cara mengubah sarang untuk loop menjadi rekursi ekor?
Dari Scala Talk di FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 di halaman 22:
Istirahat dan lanjutkan Scala tidak memilikinya. Mengapa? Mereka sedikit penting; lebih baik gunakan banyak fungsi yang lebih kecil. Masalah bagaimana berinteraksi dengan penutupan. Mereka tidak dibutuhkan!
Apa penjelasannya?
scala
for-loop
break
tail-recursion
TiansHUo
sumber
sumber
i
danj
. Jika kode ini berjalan sampai selesai tanpa keluar dari loop, hasilnya adalah906609
tetapi dengan keluar dari loop lebih awal, hasilnya adalah90909
dengan keluar dari loop tidak membuat kode "lebih efisien" karena mengubah hasil.Jawaban:
Anda memiliki tiga (atau lebih) opsi untuk keluar dari loop.
Misalkan Anda ingin menjumlahkan angka sampai total lebih besar dari 1000. Anda mencoba
kecuali Anda ingin berhenti kapan (jumlah> 1000).
Apa yang harus dilakukan? Ada beberapa opsi.
(1a) Gunakan beberapa konstruk yang mencakup persyaratan yang Anda uji.
(peringatan - ini tergantung pada detail bagaimana tes takeWhile dan foreach disisipkan selama evaluasi, dan mungkin tidak boleh digunakan dalam praktik!).
(1b) Gunakan rekursi ekor sebagai ganti for loop, manfaatkan betapa mudahnya menulis metode baru dalam Scala:
(1c) Kembali menggunakan loop sementara
(2) Melempar pengecualian.
(2a) Dalam Scala 2.8+ ini sudah dipaket sebelumnya
scala.util.control.Breaks
menggunakan sintaks yang sangat mirip dengan istirahat lama Anda yang akrab dari C / Java:(3) Masukkan kode ke dalam metode dan gunakan kembali.
Ini sengaja dibuat tidak terlalu mudah untuk setidaknya tiga alasan yang bisa saya pikirkan. Pertama, dalam blok kode besar, mudah untuk mengabaikan pernyataan "lanjutkan" dan "hancurkan", atau untuk berpikir Anda keluar lebih atau kurang dari yang sebenarnya, atau perlu mematahkan dua loop yang tidak dapat Anda lakukan tetap mudah - sehingga penggunaan standar, meskipun praktis, memiliki masalah, dan karenanya Anda harus mencoba menyusun kode dengan cara yang berbeda. Kedua, Scala memiliki semua jenis sarang yang mungkin tidak Anda sadari, jadi jika Anda bisa keluar dari masalah, Anda mungkin akan terkejut dengan di mana aliran kode berakhir (terutama dengan penutupan). Ketiga, sebagian besar "loop" Scala sebenarnya bukan loop normal - mereka adalah panggilan metode yang memiliki loop sendiri,Seperti lingkaran, sulit untuk menghasilkan cara yang konsisten untuk mengetahui apa yang harus "istirahat" dan sejenisnya. Jadi, agar konsisten, hal yang bijaksana untuk dilakukan adalah tidak memiliki "istirahat" sama sekali.
Catatan : Ada persamaan fungsional semua ini di mana Anda mengembalikan nilai
sum
alih - alih memutasikannya. Ini adalah Scala yang lebih idiomatis. Namun, logikanya tetap sama. (return
menjadireturn x
, dll.).sumber
breakable
bagian ... dan semua rintangan itu hanya untuk menghindari kejahatanbreak
, hmm ;-) Anda harus mengakui, hidup ini ironis.break
] Jika terlihat seperti abreak
dan kinerjanya sepertibreak
, sejauh yang saya ketahui itubreak
.Ini telah berubah di Scala 2.8 yang memiliki mekanisme untuk menggunakan jeda. Anda sekarang dapat melakukan hal berikut:
sumber
Tidak pernah merupakan ide yang baik untuk keluar dari for-loop. Jika Anda menggunakan for-loop itu berarti Anda tahu berapa kali Anda ingin mengulanginya. Gunakan loop sementara dengan 2 kondisi.
sebagai contoh
sumber
Untuk menambahkan Rex Kerr, jawab dengan cara lain:
(1c) Anda juga dapat menggunakan pelindung di lingkaran Anda:
sumber
Karena belum ada
break
di Scala, Anda bisa mencoba menyelesaikan masalah ini dengan menggunakan-return
pernyataan. Oleh karena itu Anda perlu menempatkan loop batin Anda ke suatu fungsi, jika tidak pengembalian akan melewati seluruh loopNamun Scala 2.8 termasuk cara untuk istirahat
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
sumber
gunakan modul Istirahat http://www.tutorialspoint.com/scala/scala_break_statement.htm
sumber
Cukup gunakan loop sementara:
sumber
Suatu pendekatan yang menghasilkan nilai-nilai pada suatu rentang seperti yang kita lakukan berulang-ulang, hingga kondisi putus, alih-alih menghasilkan pertama seluruh rentang dan kemudian mengulanginya, menggunakan
Iterator
, (terinspirasi oleh penggunaan @RexKerrStream
)sumber
Berikut ini adalah versi rekursif ekor. Dibandingkan dengan untuk-pemahaman itu agak samar, memang, tapi saya akan mengatakan itu fungsional :)
Seperti yang Anda lihat, fungsi tr adalah padanan dari bagian luar untuk pemahaman, dan tr1 dari bagian dalam. Sama-sama jika Anda tahu cara mengoptimalkan versi saya.
sumber
Yang dekat dengan solusi Anda adalah ini:
J-iterasi dibuat tanpa ruang lingkup baru, dan pembuatan produk serta kondisinya dilakukan dalam for-statement (bukan ekspresi yang baik - saya tidak menemukan yang lebih baik). Kondisi terbalik yang cukup cepat untuk ukuran masalah itu - mungkin Anda mendapatkan sesuatu dengan istirahat untuk loop yang lebih besar.
String.reverse secara implisit mengkonversi ke RichString, itulah sebabnya saya melakukan 2 pembalikan ekstra. :) Pendekatan yang lebih matematis mungkin lebih elegan.
sumber
breakable
Paket pihak ketiga adalah salah satu alternatif yang memungkinkanhttps://github.com/erikerlandson/breakable
Kode contoh:
sumber
Metode dasar untuk memutus loop, menggunakan kelas Breaks. Dengan mendeklarasikan loop sebagai breakable.
sumber
Sederhananya yang bisa kita lakukan di scala adalah
keluaran:
sumber
Ironisnya, pembobolan Scala
scala.util.control.Breaks
adalah pengecualian:Saran terbaik adalah: JANGAN menggunakan istirahat, lanjutkan dan kebagian! IMO mereka sama, praktik buruk dan sumber jahat dari semua jenis masalah (dan diskusi panas) dan akhirnya "dianggap berbahaya". Blok kode terstruktur, juga dalam contoh ini jeda adalah berlebihan. Edsger W. Dijkstra kami † menulis:
sumber
Saya mendapat situasi seperti kode di bawah ini
Saya menggunakan java lib dan mekanismenya adalah ctx.read membuang Exception ketika tidak menemukan apa-apa. Saya terjebak dalam situasi itu: Saya harus memutus loop ketika Exception dilemparkan, tetapi scala.util.control.Breaks.break menggunakan Exception untuk memutus loop, dan itu ada di catch block sehingga tertangkap.
Saya punya cara jelek untuk menyelesaikan ini: lakukan perulangan untuk pertama kalinya dan dapatkan hitungan dari panjang sebenarnya. dan gunakan untuk loop kedua.
mengambil istirahat dari Scala tidak begitu baik, ketika Anda menggunakan beberapa lib java.
sumber
Saya baru di Scala, tetapi bagaimana dengan ini untuk menghindari melemparkan pengecualian dan metode berulang:
gunakan seperti ini:
jika Anda tidak ingin istirahat:
sumber
Penggunaan
find
metode pengumpulan yang cerdik akan membantu Anda.sumber
sumber
Saya tidak tahu berapa banyak gaya Scala telah berubah dalam 9 tahun terakhir, tetapi saya merasa menarik bahwa sebagian besar jawaban yang ada menggunakan
vars
, atau sulit untuk membaca rekursi. Kunci untuk keluar lebih awal adalah dengan menggunakan koleksi malas untuk menghasilkan calon yang memungkinkan Anda, kemudian periksa kondisinya secara terpisah. Untuk menghasilkan produk:Kemudian untuk menemukan palindrome pertama dari tampilan itu tanpa menghasilkan setiap kombinasi:
Untuk menemukan palindrome terbesar (walaupun kemalasan tidak banyak membeli Anda karena Anda harus memeriksa seluruh daftar):
Kode asli Anda sebenarnya memeriksa palindrom pertama yang lebih besar dari produk berikutnya, yang sama dengan memeriksa palindrom pertama kecuali dalam kondisi batas aneh yang menurut saya tidak Anda maksudkan. Produk tidak sepenuhnya menurun secara monoton. Misalnya,
998*998
lebih besar dari999*997
, tetapi muncul jauh di loop.Lagi pula, keuntungan dari generasi malas yang terpisah dan kondisi memeriksa adalah Anda menulisnya cukup banyak seperti menggunakan seluruh daftar, tetapi hanya menghasilkan sebanyak yang Anda butuhkan. Anda mendapatkan yang terbaik dari kedua dunia.
sumber