ฉันจะแยกวงใน Scala ได้อย่างไร


276

ฉันจะแยกวงได้อย่างไร

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
    }
}

ฉันจะเปลี่ยนลูปเป็นลูปเป็นการวนรอบแบบวนซ้ำได้อย่างไร?

จาก Scala Talk ที่ FOSDEM 2009 http://www.slideshare.net/Odersky/fosdem-2009-1013261 ในหน้า 22:

ทำลายและดำเนินการต่อสกาล่าไม่ได้มีพวกเขา ทำไม? พวกเขามีความจำเป็นเล็กน้อย ดีกว่าใช้ฟังก์ชั่นขนาดเล็กจำนวนมากออกวิธีการโต้ตอบกับการปิด พวกเขาไม่ต้องการ!

คำอธิบายคืออะไร


การเปรียบเทียบของคุณจำเป็นต้องมีเครื่องหมายเท่ากับสองเท่ากับ: if (product.toString == product.toString.reverse) หรืออาจเท่ากับวิธีการโทร
ผู้ใช้ไม่รู้จัก

ใช่ฉันพลาดไปเมื่อฉันพิมพ์ใน
TiansHUo

ฉันรู้ว่าฉันฟื้นคืนชีพคำถามเก่า แต่ฉันชอบที่จะรู้ว่าจุดประสงค์ของรหัสนี้คืออะไร? ครั้งแรกที่ผมคิดว่าคุณกำลังพยายามที่จะหาที่ใหญ่ที่สุด "palindrome" ผลิตภัณฑ์ที่เป็นไปได้กับชุดที่กำหนดและi jหากโค้ดนี้ทำงานจนเสร็จสมบูรณ์โดยไม่แยกจากลูปผลลัพธ์จะเกิด906609จากการแยกลูป แต่เนิ่นๆผลที่ได้คือการ90909แตกออกจากลูปนั้นไม่ได้ทำให้โค้ด "มีประสิทธิภาพมากขึ้น" เนื่องจากมีการเปลี่ยนแปลงผลลัพธ์
Ryan H.

คำตอบ:


371

คุณมีสามตัวเลือก (หรือมากกว่านั้น) ที่จะแยกออกจากลูป

สมมติว่าคุณต้องการหาผลรวมตัวเลขจนกว่าผลรวมจะมากกว่า 1,000 คุณลอง

var sum = 0
for (i <- 0 to 1000) sum += i

ยกเว้นคุณต้องการหยุดเมื่อ (รวม> 1,000)

จะทำอย่างไร? มีหลายตัวเลือก

(1a) ใช้โครงสร้างที่มีเงื่อนไขที่คุณทดสอบ

var sum = 0
(0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i)

(คำเตือน - สิ่งนี้ขึ้นอยู่กับรายละเอียดว่าการทดสอบแบบ TakeWhile และ foreach นั้นเป็นอย่างไรในระหว่างการประเมินผลและอาจไม่ควรใช้ในทางปฏิบัติ!)

(1b) ใช้การเรียกซ้ำแบบหางแทนการวนซ้ำเพื่อใช้ประโยชน์จากความง่ายในการเขียนวิธีการใหม่ใน Scala:

var sum = 0
def addTo(i: Int, max: Int) {
  sum += i; if (sum < max) addTo(i+1,max)
}
addTo(0,1000)

(1c) ถอยกลับไปใช้ลูปสักครู่

var sum = 0
var i = 0
while (i <= 1000 && sum <= 1000) { sum += 1; i += 1 }

(2) โยนข้อยกเว้น

object AllDone extends Exception { }
var sum = 0
try {
  for (i <- 0 to 1000) { sum += i; if (sum>=1000) throw AllDone }
} catch {
  case AllDone =>
}

(2a) ใน Scala 2.8+ สิ่งนี้ได้รับการจัดทำแพ็กเกจไว้ล่วงหน้าในการscala.util.control.Breaksใช้ไวยากรณ์ที่มีลักษณะเหมือนตัวแบ่งเก่าที่คุณคุ้นเคยจาก C / Java:

import scala.util.control.Breaks._
var sum = 0
breakable { for (i <- 0 to 1000) {
  sum += i
  if (sum >= 1000) break
} }

(3) ใส่รหัสในวิธีการและใช้ผลตอบแทน

var sum = 0
def findSum { for (i <- 0 to 1000) { sum += i; if (sum>=1000) return } }
findSum

สิ่งนี้ถูกสร้างขึ้นโดยเจตนาไม่ง่ายเกินไปด้วยเหตุผลอย่างน้อยสามประการที่ฉันสามารถนึกถึง ก่อนอื่นในบล็อคโค้ดขนาดใหญ่มันง่ายที่จะมองข้ามคำสั่ง "ทำต่อไป" และ "หยุด" หรือคิดว่าคุณแยกออกไม่มากไปกว่าที่คุณเป็นจริงหรือต้องแบ่งสองลูปที่คุณไม่สามารถทำได้ อย่างไรก็ตามการใช้งานมาตรฐานในขณะที่สะดวกมีปัญหาและทำให้คุณควรพยายามจัดโครงสร้างโค้ดของคุณในวิธีที่ต่างออกไป ประการที่สองสกาล่ามีการทำรังทุกประเภทที่คุณอาจไม่สังเกตเห็นดังนั้นถ้าคุณสามารถแยกแยะสิ่งต่าง ๆ ออกมาได้คุณอาจจะประหลาดใจกับที่การไหลของรหัสสิ้นสุดลง (โดยเฉพาะอย่างยิ่งกับการปิด) ประการที่สาม "ลูป" ของสกาล่าส่วนใหญ่ไม่ใช่ลูปปกติจริง ๆ - พวกเขาเรียกวิธีใช้ที่มีการวนซ้ำของตัวเองการวนซ้ำมันยากที่จะเกิดขึ้นด้วยวิธีที่สอดคล้องกันเพื่อรู้ว่า "หยุด" และสิ่งที่ควรทำ ดังนั้นเพื่อให้สอดคล้องสิ่งที่ควรทำคือไม่ต้องมี "การหยุด" เลย

หมายเหตุ : มีฟังก์ชันที่เทียบเท่ากับสิ่งเหล่านี้ทั้งหมดที่คุณส่งคืนค่าsumแทนที่จะกลายพันธุ์แทน เหล่านี้เป็น Scala สำนวนมากขึ้น อย่างไรก็ตามตรรกะยังคงเหมือนเดิม ( returnกลายเป็นreturn xฯลฯ )


9
Re ข้อยกเว้นแม้ว่าจะเป็นความจริงอย่างเคร่งครัดว่าคุณสามารถโยนข้อยกเว้นได้นี่เป็นการละเมิดกลไกการยกเว้น (ดู Java ที่มีประสิทธิภาพ) ข้อยกเว้นเป็นการบ่งชี้สถานการณ์ที่ไม่คาดคิดอย่างแท้จริงและ / หรือต้องการการหลีกเลี่ยงอย่างมากจากรหัสนั่นคือข้อผิดพลาดบางอย่าง นอกเหนือจากนั้นพวกเขาเคยค่อนข้างช้า (ไม่แน่ใจเกี่ยวกับสถานการณ์ปัจจุบัน) เนื่องจากมีเหตุผลเล็กน้อยสำหรับ JVM ที่จะปรับให้เหมาะสม
Jonathan

28
@ โจนาธาน - ข้อยกเว้นจะช้าก็ต่อเมื่อคุณจำเป็นต้องคำนวณสแต็กติดตาม - สังเกตว่าฉันสร้างข้อยกเว้นแบบคงที่เพื่อโยนแทนที่จะสร้างมันขึ้นมาทันที! และพวกมันเป็นโครงสร้างควบคุมที่ถูกต้องสมบูรณ์แบบ มันถูกใช้ในหลาย ๆ ที่ทั่วทั้งห้องสมุดสกาล่าเนื่องจากเป็นวิธีเดียวที่คุณสามารถกลับมาได้หลายวิธี (ซึ่งถ้าคุณมีกองปิดเป็นสิ่งที่คุณต้องทำ)
Rex Kerr

18
@Rex Kerr คุณกำลังชี้ให้เห็นถึงจุดอ่อนของโครงสร้าง break (ฉันไม่เห็นด้วยกับพวกเขา) แต่คุณแนะนำให้ใช้ข้อยกเว้นสำหรับเวิร์กโฟลว์ปกติ! การออกจากลูปไม่ใช่กรณีพิเศษมันเป็นส่วนหนึ่งของอัลกอริทึมไม่ใช่กรณีของการเขียนไปยังไฟล์ที่ไม่มีอยู่ (ตัวอย่าง) ดังนั้นในระยะสั้นแนะนำ "รักษา" เลวร้ายยิ่งกว่า "ความเจ็บป่วย" ตัวเอง และเมื่อฉันพิจารณาโยนข้อยกเว้นที่แท้จริงในbreakableส่วน ... และห่วงเหล่านั้นเพียงเพื่อหลีกเลี่ยงความชั่วร้ายbreakอืม ;-) คุณต้องยอมรับว่าชีวิตเป็นเรื่องน่าขัน
greenoldman

17
@macias - ขออภัยความผิดพลาดของฉัน JVM ใช้ Throwables สำหรับการควบคุมโฟลว์ ดีขึ้นหรือไม่ เพียงเพราะพวกเขามักจะใช้เพื่อรองรับการจัดการข้อยกเว้นไม่ได้หมายความว่าพวกเขาสามารถใช้สำหรับการจัดการข้อยกเว้นเท่านั้น การกลับไปยังตำแหน่งที่กำหนดจากภายในการปิดเป็นเหมือนการทิ้งข้อยกเว้นในแง่ของการควบคุมการไหล ไม่แปลกใจเลยว่านี่คือกลไกที่ใช้
Rex Kerr

14
@RexKerr ดีสำหรับสิ่งที่คุ้มค่าที่คุณเชื่อฉัน ปกติฉันจะเป็นคนหนึ่งในการต่อต้านข้อยกเว้นสำหรับโฟลว์โปรแกรมปกติ แต่เหตุผลหลักสองข้อที่ไม่ได้ใช้ที่นี่ เหล่านี้คือ (1) การที่พวกเขากำลังช้า [ไม่เมื่อใช้วิธีนี้] และ (2) พวกเขาแนะนำพฤติกรรมพิเศษให้กับคนอ่านรหัสของคุณ [ไม่ถ้าห้องสมุดของคุณช่วยให้คุณสามารถเรียกพวกเขาbreak] ถ้ามันมีลักษณะเหมือนbreakและจะดำเนินการ เหมือนเท่าที่ฉันกังวลมันเป็นbreak break
ทิมกู๊ดแมน

66

สิ่งนี้มีการเปลี่ยนแปลงใน Scala 2.8 ซึ่งมีกลไกสำหรับการใช้ตัวแบ่ง ตอนนี้คุณสามารถทำสิ่งต่อไปนี้:

import scala.util.control.Breaks._
var largest = 0
// pass a function to the breakable method
breakable { 
    for (i<-999 to 1  by -1; j <- i to 1 by -1) {
        val product = i * j
        if (largest > product) {
            break  // BREAK!!
        }
        else if (product.toString.equals(product.toString.reverse)) {
            largest = largest max product
        }
    }
}

3
สิ่งนี้ใช้ข้อยกเว้นภายใต้ประทุนหรือไม่?
Mike

นี่คือการใช้ Scala เป็นภาษาขั้นตอนโดยไม่สนใจข้อดีของการเขียนโปรแกรมการทำงาน (เช่นการเรียกซ้ำหาง) ไม่สวย.
Galder Zamarreño

32
Mike: ใช่ Scala กำลังขว้างข้อยกเว้นให้หลุดออกจากวง Galder: นี่เป็นคำตอบของคำถามที่โพสต์ว่า "ฉันจะแยกวงวนใน Scala ได้อย่างไร" ไม่ว่าจะเป็น 'สวย' หรือไม่เกี่ยวข้อง
hohonuuli

2
@hohonuuli ดังนั้นในการลองจับมันจะไม่แตกใช่มั้ย
greenoldman

2
@Gderder Zamarreñoเหตุใดการเรียกหางกลับมาเป็นข้อได้เปรียบในกรณีนี้คืออะไร? ไม่ใช่เพียงการเพิ่มประสิทธิภาพ (แอปพลิเคชันของผู้ที่ถูกซ่อนไว้สำหรับผู้มาใหม่และนำมาใช้อย่างสับสนสำหรับผู้ที่มีประสบการณ์) มีประโยชน์สำหรับการเรียกซ้ำแบบหางในตัวอย่างนี้หรือไม่?
user48956

32

มันเป็นความคิดที่ดีที่จะแยกออกจาก for-loop หากคุณใช้ for-loop หมายความว่าคุณรู้ว่าคุณต้องการวนซ้ำกี่ครั้ง ใช้ while-loop กับ 2 เงื่อนไข

ตัวอย่างเช่น

var done = false
while (i <= length && !done) {
  if (sum > 1000) {
     done = true
  }
}

2
นี่คือสิ่งที่ฉันรู้สึกว่าเป็นวิธีที่เหมาะสมในการแยกลูปในสกาลา มีอะไรผิดปกติกับคำตอบนี้หรือไม่? (พิจารณาจำนวน upvotes ต่ำ)
Jus12

1
เรียบง่ายและอ่านง่ายขึ้น แม้สิ่งที่เปราะบาง - แตกก็ถูกต้องมันดูน่าเกลียดและมีปัญหากับการลองจับภายใน แม้ว่าวิธีการแก้ปัญหาของคุณจะไม่ทำงานกับ foreach ฉันจะลงคะแนนคุณให้ความเคารพความเรียบง่าย
yerlilbilgin

13

หากต้องการเพิ่ม Rex Kerr ให้ตอบอีกทางหนึ่ง:

  • (1c) คุณยังสามารถใช้ตัวป้องกันในวงของคุณ:

     var sum = 0
     for (i <- 0 to 1000 ; if sum<1000) sum += i

30
ฉันไม่ได้รวมสิ่งนี้ไว้เป็นตัวเลือกเพราะจริงๆแล้วมันไม่ได้แบ่งลูป - มันวิ่งผ่านมันทั้งหมด แต่คำสั่ง if ล้มเหลวในการวนซ้ำทุกครั้งหลังจากผลรวมนั้นสูงพอ มูลค่าการทำงานในแต่ละครั้ง ขออภัยขึ้นอยู่กับวิธีที่คุณเขียนลูปนั้นอาจเป็นงานจำนวนมาก
Rex Kerr

@RexKerr: คอมไพเลอร์จะไม่เพิ่มประสิทธิภาพหรือไม่ จะไม่ถูกปรับให้เหมาะสมถ้าไม่ใช่ในระหว่างการเรียกใช้ครั้งแรกในช่วง JIT
Maciej Piechotka

5
@MaciejPiechotka - โดยทั่วไปคอมไพเลอร์ JIT ไม่มีตรรกะที่ซับซ้อนเพียงพอที่จะรับรู้ว่าคำสั่ง if บนตัวแปรที่เปลี่ยนแปลงจะเสมอ (ในสถานการณ์พิเศษนี้) ส่งคืนค่าเท็จและสามารถละเว้นได้
Rex Kerr

6

เนื่องจากยังไม่มีbreakใน Scala คุณสามารถลองแก้ปัญหานี้ด้วยการใช้คำreturnสั่ง ดังนั้นคุณต้องใส่วงภายในของคุณเข้าไปในฟังก์ชั่นมิฉะนั้นการคืนจะข้ามทั้งวง

สกาล่า 2.8 อย่างไรก็ตามรวมถึงวิธีการทำลาย

http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html


ขอโทษ แต่ฉันแค่อยากจะแยกวงด้านในออก คุณไม่ได้หมายความว่าฉันควรใส่มันไว้ในฟังก์ชั่นใช่มั้ย
TiansHUo

ขออภัยควรมีคำชี้แจงว่า แน่นอนว่าการใช้การส่งคืนหมายความว่าคุณต้องแค็ปซูลลูปในฟังก์ชัน ฉันแก้ไขคำตอบของฉันแล้ว
Ham Vocke

1
นั่นไม่ดีเลย ดูเหมือนว่าสกาล่าไม่ชอบลูปซ้อนกัน
TiansHUo

ดูเหมือนจะไม่มีวิธีอื่น คุณอาจต้องการดูสิ่งนี้: scala-lang.org/node/257
Ham Vocke

4
@TiansHUo: ทำไมคุณถึงบอกว่า Scala ไม่ชอบลูปซ้อนกัน ? คุณมีปัญหาเดียวกันถ้าคุณพยายามแยกออกจากวงเดียว
Rex Kerr



5

วิธีการที่สร้างค่าในช่วงที่เราทำซ้ำจนถึงสภาพที่แตกหักแทนที่จะสร้างช่วงแรกทั้งช่วงจากนั้นวนซ้ำโดยใช้Iterator(สร้างแรงบันดาลใจในการใช้ @RexKerr Stream)

var sum = 0
for ( i <- Iterator.from(1).takeWhile( _ => sum < 1000) ) sum += i

ใช่ฉันชอบมัน. ไม่มีข้อแก้ตัวที่เปราะบางฉันคิดว่ามันดูดีกว่า
ses

4

นี่คือหางแบบเรียกซ้ำ เปรียบเทียบกับความเข้าใจมันเป็นความลับเล็กน้อยยอมรับ แต่ฉันบอกว่ามันทำงาน :)

def run(start:Int) = {
  @tailrec
  def tr(i:Int, largest:Int):Int = tr1(i, i, largest) match {
    case x if i > 1 => tr(i-1, x)
    case _ => largest
  }

  @tailrec
  def tr1(i:Int,j:Int, largest:Int):Int = i*j match {
    case x if x < largest || j < 2 => largest
    case x if x.toString.equals(x.toString.reverse) => tr1(i, j-1, x)
    case _ => tr1(i, j-1, largest)
  }

  tr(start, 0)
}

อย่างที่คุณเห็นฟังก์ชั่น tr คือคู่ของด้านนอกเพื่อความเข้าใจและ tr1 ของด้านใน คุณยินดีถ้าคุณรู้วิธีเพิ่มประสิทธิภาพรุ่นของฉัน


2

ใกล้กับโซลูชันของคุณจะเป็นดังนี้:

var largest = 0
for (i <- 999 to 1 by -1;
  j <- i to 1 by -1;
  product = i * j;
  if (largest <= product && product.toString.reverse.equals (product.toString.reverse.reverse)))
    largest = product

println (largest)

การทำซ้ำ j- ทำโดยไม่มีขอบเขตใหม่และการสร้างผลิตภัณฑ์เช่นเดียวกับเงื่อนไขที่ทำในคำสั่งสำหรับ (ไม่แสดงออกที่ดี - ฉันไม่พบที่ดีกว่า) เงื่อนไขถูกย้อนกลับซึ่งค่อนข้างเร็วสำหรับขนาดของปัญหานั้น - บางทีคุณอาจได้รับบางสิ่งบางอย่างพร้อมกับแบ่งสำหรับลูปขนาดใหญ่

String.reverse แปลงเป็น RichString โดยปริยายซึ่งเป็นสาเหตุที่ฉันย้อนกลับ 2 ครั้ง :) วิธีทางคณิตศาสตร์ที่มากขึ้นอาจจะดูสง่างามกว่า


2

breakableแพ็คเกจของบุคคลที่สามเป็นทางเลือกหนึ่งที่เป็นไปได้

https://github.com/erikerlandson/breakable

รหัสตัวอย่าง:

scala> import com.manyangled.breakable._
import com.manyangled.breakable._

scala> val bkb2 = for {
     |   (x, xLab) <- Stream.from(0).breakable   // create breakable sequence with a method
     |   (y, yLab) <- breakable(Stream.from(0))  // create with a function
     |   if (x % 2 == 1) continue(xLab)          // continue to next in outer "x" loop
     |   if (y % 2 == 0) continue(yLab)          // continue to next in inner "y" loop
     |   if (x > 10) break(xLab)                 // break the outer "x" loop
     |   if (y > x) break(yLab)                  // break the inner "y" loop
     | } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2

scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))

2
import scala.util.control._

object demo_brk_963 
{
   def main(args: Array[String]) 
   {
      var a = 0;
      var b = 0;
      val numList1 = List(1,2,3,4,5,6,7,8,9,10);
      val numList2 = List(11,12,13);

      val outer = new Breaks; //object for break
      val inner = new Breaks; //object for break

      outer.breakable // Outer Block
      {
         for( a <- numList1)
         {
            println( "Value of a: " + a);

            inner.breakable // Inner Block
            {
               for( b <- numList2)
               {
                  println( "Value of b: " + b);

                  if( b == 12 )
                  {
                      println( "break-INNER;");
                       inner.break;
                  }
               }
            } // inner breakable
            if( a == 6 )
            {
                println( "break-OUTER;");
                outer.break;
            }
         }
      } // outer breakable.
   }
}

วิธีการพื้นฐานในการแบ่งลูปโดยใช้คลาส Breaks ด้วยการประกาศลูปเป็นเปราะบาง


2

เพียงเราสามารถทำได้ในสกาล่าคือ

scala> import util.control.Breaks._

scala> object TestBreak{
       def main(args : Array[String]){
       breakable {
       for (i <- 1 to 10){
       println(i)
       if (i == 5){
       break;
       } } } } }

ผลลัพธ์:

scala> TestBreak.main(Array())
1
2
3
4
5

1

กระแทกแดกดันการแบ่งสกาล่าscala.util.control.Breaksเป็นข้อยกเว้น:

def break(): Nothing = { throw breakException }

คำแนะนำที่ดีที่สุดคือ: อย่าหยุดพักทำต่อไปและกลับไป! IMO พวกเขาเหมือนกันการปฏิบัติที่ไม่ดีและแหล่งที่มาที่ชั่วร้ายของปัญหาทุกประเภท (และการสนทนาที่ร้อนแรง) และในที่สุด "ถือว่าเป็นอันตราย" โครงสร้างบล็อกโค้ดในตัวแบ่งตัวอย่างนี้จะไม่จำเป็น Edsger W. Dijkstra †ของเราเขียนว่า:

คุณภาพของโปรแกรมเมอร์คือฟังก์ชั่นลดลงของความหนาแน่นของการไปงบในโปรแกรมที่พวกเขาผลิต


1

ฉันได้รับสถานการณ์เช่นรหัสด้านล่าง

 for(id<-0 to 99) {
    try {
      var symbol = ctx.read("$.stocks[" + id + "].symbol").toString
      var name = ctx.read("$.stocks[" + id + "].name").toString
      stocklist(symbol) = name
    }catch {
      case ex: com.jayway.jsonpath.PathNotFoundException=>{break}
    }
  }

ฉันใช้ java lib และกลไกก็คือ ctx.read จะทำการยกเว้นเมื่อมันไม่พบอะไรเลย ฉันถูกขังอยู่ในสถานการณ์ที่: ฉันต้องทำลายลูปเมื่อมีการโยนข้อยกเว้น แต่ scala.util.control.Breaks.break โดยใช้ข้อยกเว้นเพื่อแยกลูปและอยู่ในบล็อกการบล็อกดังนั้นจึงถูกจับได้

ฉันมีวิธีที่น่าเกลียดในการแก้ปัญหานี้: ทำลูปเป็นครั้งแรกและนับความยาวจริง และใช้สำหรับวงที่สอง

การหยุดพักจาก Scala นั้นไม่ค่อยดีนักเมื่อคุณใช้ Java libs บางตัว


1

ฉันยังใหม่กับสกาล่า แต่วิธีนี้จะหลีกเลี่ยงการโยนข้อยกเว้นและวิธีการทำซ้ำ:

object awhile {
def apply(condition: () => Boolean, action: () => breakwhen): Unit = {
    while (condition()) {
        action() match {
            case breakwhen(true)    => return ;
            case _                  => { };
        }
    }
}
case class breakwhen(break:Boolean);

ใช้มันแบบนี้:

var i = 0
awhile(() => i < 20, () => {
    i = i + 1
    breakwhen(i == 5)
});
println(i)

หากคุณไม่ต้องการทำลาย:

awhile(() => i < 20, () => {
    i = i + 1
    breakwhen(false)
});

1

การใช้findวิธีการเก็บอย่างชาญฉลาดจะทำเคล็ดลับสำหรับคุณ

var largest = 0
lazy val ij =
  for (i <- 999 to 1 by -1; j <- i to 1 by -1) yield (i, j)

val largest_ij = ij.find { case(i,j) =>
  val product = i * j
  if (product.toString == product.toString.reverse)
    largest = largest max product
  largest > product
}

println(largest_ij.get)
println(largest)

1

ด้านล่างเป็นรหัสที่จะทำลายวงในวิธีที่ง่าย

import scala.util.control.Breaks.break

object RecurringCharacter {
  def main(args: Array[String]) {
    val str = "nileshshinde";

    for (i <- 0 to str.length() - 1) {
      for (j <- i + 1 to str.length() - 1) {

        if (str(i) == str(j)) {
          println("First Repeted Character " + str(i))
          break()     //break method will exit the loop with an Exception "Exception in thread "main" scala.util.control.BreakControl"

        }
      }
    }
  }
}

1

ฉันไม่ทราบว่ารูปแบบสกาล่ามีการเปลี่ยนแปลงมากน้อยเพียงใดในช่วง 9 ปีที่ผ่านมา แต่ฉันพบว่ามันน่าสนใจที่คำตอบที่มีอยู่ส่วนใหญ่ใช้varsหรือเรียกอ่านซ้ำ กุญแจสำคัญในการออกก่อนกำหนดคือการใช้คอลเล็กชันขี้เกียจเพื่อสร้างผู้สมัครที่เป็นไปได้ของคุณจากนั้นตรวจสอบเงื่อนไขแยกกัน เพื่อสร้างผลิตภัณฑ์:

val products = for {
  i <- (999 to 1 by -1).view
  j <- (i to 1 by -1).view
} yield (i*j)

จากนั้นเพื่อค้นหา palindrome แรกจากมุมมองนั้นโดยไม่สร้างชุดค่าผสมทั้งหมด:

val palindromes = products filter {p => p.toString == p.toString.reverse}
palindromes.head

หากต้องการค้นหา palindrome ที่ใหญ่ที่สุด (แม้ว่าความขี้เกียจจะไม่ซื้อคุณมากนักเพราะคุณต้องตรวจสอบรายชื่อทั้งหมด):

palindromes.max

รหัสต้นฉบับของคุณกำลังตรวจสอบ palindrome แรกที่มีขนาดใหญ่กว่าผลิตภัณฑ์ที่ตามมาซึ่งเหมือนกับการตรวจสอบ palindrome แรกยกเว้นในสภาพขอบเขตที่แปลกซึ่งฉันไม่คิดว่าคุณตั้งใจจะทำ ผลิตภัณฑ์ไม่ได้ลดความซ้ำซากจำเจอย่างเคร่งครัด ตัวอย่างเช่น998*998มีค่ามากกว่า999*997แต่จะปรากฏขึ้นภายหลังในลูป

อย่างไรก็ตามข้อดีของการสร้างรุ่นสันหลังยาวและการตรวจสอบเงื่อนไขคือคุณเขียนมันเหมือนว่ามันใช้รายการทั้งหมด แต่สร้างได้มากเท่าที่คุณต้องการ คุณจะได้รับสิ่งที่ดีที่สุดของทั้งสองโลก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.