简体   繁体   English

在列表上迭代时打破Scala中的循环

[英]Break out of loop in scala while iterating on list

I am trying to solve a problem. 我正在尝试解决问题。

Problem : You are given a sequence of N balls in 4 colors: red, green, yellow and blue. 问题:您将获得N球序列,该球有4种颜色:红色,绿色,黄色和蓝色。 The sequence is full of colors if and only if all of the following conditions are true: 当且仅当满足以下所有条件时,序列中才会充满颜色:

There are as many red balls as green balls. 红球和绿球一样多。 There are as many yellow balls as blue balls. 黄色球和蓝色球一样多。 Difference between the number of red balls and green balls in every prefix of the sequence is at most 1. Difference between the number of yellow balls and blue balls in every prefix of the sequence is at most 1. Your task is to write a program, which for a given sequence prints True if it is full of colors, otherwise it prints False. 该序列的每个前缀中的红色球和绿色球的数量之间的差异最大为1。序列的每个前缀中的黄球和蓝色球的数量之间的差异最大为1。您的任务是编写一个程序,如果给定的序列充满了颜色,则它会打印True,否则会打印False。

My solution : for each string, i am generating all possible prefixes and suffixes to validate the condition number 3 and 4. But it is taking more time. 我的解决方案:对于每个字符串,我都会生成所有可能的前缀和后缀以验证条件编号3和4。但是,这需要更多时间。

instead of generating prefix and validating conditions every time, we can iterate over the string and validate the condition. 无需每次都生成前缀和验证条件,我们可以遍历字符串并验证条件。 I want to break out of loop when condition is not met. 我想在不满足条件时打破循环。 I am not able to get that in functional style. 我无法以实用的风格得到它。 Can someone help me how to achieve it. 有人可以帮助我如何实现它。

My solution : 我的解决方案:

object Test {

    def main(args: Array[String]) {

      def isValidSequence(str: String) = {
        def isValidCondition(ch1:Char, ch2:Char, m:Map[Char, Int]):Boolean = m.getOrElse(ch1, 0) - m.getOrElse(ch2, 0) > 1
        def groupByChars(s:String) = s.groupBy(ch => ch).map(x => (x._1, x._2.length))
        def isValidPrefix(s:String):Boolean = (1 to s.length).exists(x => isValidCondition('R', 'G', groupByChars(s.take(x))))

        val x = groupByChars(str)
        lazy val cond1 = x.get('R') == x.get('G')
        lazy val cond2 = x.get('B') == x.get('Y')
        lazy val cond3 = isValidPrefix(str)
        lazy val cond4 = isValidPrefix(str.reverse)

        cond1 && cond2 && !cond3 && !cond4
      }
      def printBoolValue(b:Boolean) = if(b) println("True") else println("False")

      val in = io.Source.stdin.getLines()
      val inSize = in.take(1).next().toInt
      val strs = in.take(inSize)
      strs.map(isValidSequence(_)).foreach(printBoolValue)
    }
}

As another answer, here's a more straightforward solution, that does short-circuit the differences check. 另一个答案是,这是一个更直接的解决方案,它可以使差异检查短路。

val valid = List("RGYBRGYB")      
val invalid = List("RGYBR", "RGYBY", "RGYBY", "RGYYB")

def checkBalls(s:String) = {
def differences(s:String, a:Char, b:Char) = {
  def differenceHelp(s:String, a:Char, b:Char, current:Int):Boolean = {
      if (current < -1 || current > 1) false
      else if (s.length == 0) true
      else differenceHelp(s.tail, a, b,
           if (s.head == a) current + 1 else if (s.head == b) current - 1 else current)
    }

  differenceHelp(s, a, b, 0)
}

lazy val cond1 = s.count('R'==) == s.count('G'==)
lazy val cond2 = s.count('Y'==) == s.count('B'==)
lazy val cond3 = differences(s, 'R', 'G')
lazy val cond4 = differences(s, 'Y', 'B')
cond1 && cond2 && cond3 && cond4
} 
valid.forall(checkBalls(_))                       //> res0: Boolean = true
invalid.forall(!checkBalls(_))                    //> res1: Boolean = true

EDIT: as an optimisation, we can do cond1 as part of cond3 (and cond2 as part of cond4). 编辑:作为优化,我们可以将cond1作为cond3的一部分(和cond2作为cond4的一部分)。 There are equal numbers of each if and only if the count is 0 at the end of the string. 当且仅当字符串末尾的计数为0时,每个数字相等。 We can check that in differences and return true only if that's the case. 我们可以检查差异并仅在这种情况下返回true。 So that gives 所以给

def checkBalls(s:String) = {
def differences(s:String, a:Char, b:Char) = {
  def differenceHelp(s:String, a:Char, b:Char, current:Int):Boolean = {
      if (current < -1 || current > 1) false
      else if (s.length == 0) (count == 0) // <- this line changed
      else differenceHelp(s.tail, a, b,
           if (s.head == a) current + 1 else if (s.head == b) current - 1 else current)
    }

  differenceHelp(s, a, b, 0)
}

lazy val cond3 = differences(s, 'R', 'G')
lazy val cond4 = differences(s, 'Y', 'B')
cond3 && cond4
} 

which passes the tests just like the previous version. 通过测试就像以前的版本一样。 It could be made slightly faster by doing the R/G and Y/B checks in one call to differences , but that's looking a bit overspecialised. 通过一次调用differences来进行R / G和Y / B检查,可以使其速度稍快一些,但这看起来有些专业化了。

So, the trick is to check the longest prefix first. 因此,诀窍是首先检查最长的前缀。 If that fails, we're done. 如果失败,我们就完成了。 Otherwise, we take the next longest prefix and recurse. 否则,我们采用下一个最长的前缀并递归。 If we get to the empty string, it passed for all prefixes, and therefore it's valid. 如果我们到达空字符串,则为所有前缀传递该字符串,因此它是有效的。

def isValidPrefix(s: String): Boolean = 
if (s.length == 0)
  true
else if (!isValidCondition('R', 'G', groupByChars(s)))
  false
else isValidPrefix(s.init)

Here is a solution using streams if you need. 如果需要,这是使用流的解决方案。

code :- 代码:-

object RGYB extends App {

val validPattern = List(
        "RG","RYBG","RYGB","RBGY",
        "GR","GYBR","GYRB","GBRY",
        "YB","YRGB","YRBG","YGRB",
        "BY","BRGY","BRYG","BGYR"
        )

        val pattern ="RGRG"
        pattern.sliding(4).foreach { x1 =>
        val count = validPattern.filter { p1 => {
            x1.equalsIgnoreCase(p1)
        } 
        }.size
        if(count<1)
        {
            x1.sliding(2).foreach {
                x2=>
                val counter  = validPattern.filter { p2 => {
                    x2.equalsIgnoreCase(p2)
                } 
                }.size
                if(counter<1)
                {
                    println("false !! not valid due to "+x2);
                    System.exit(0)
                }
            }
            println("false !! not valid due to "+x1);
            System.exit(0)
        }
}

println("True !!"+pattern+" Is a valid string pattern")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM