Scala方式一个接一个地查找元素

时间:2019-01-21 10:09:24

标签: scala functional-programming

我正在寻找在给定具有以下逻辑的List [String]时返回true或false的方法。

  • 当A在列表中时,该列表被称为“ 1开始”
  • 当字符串“ B”之后有字符串“ C”时,该列表被称为“ 2开始”

例如

  • [A,B,Z]此列表为“ 1开始”,而不是“ 2开始”
  • [A,B,Z,C]此列表“ 2开始”和“ 1开始”

现在我想要一个函数hasTwoStarts,如果列表中有任何开头,然后是两个中的任何一个,它将返回该函数。这意味着以下任何组合应返回true:

"1 start" "1 start" [A, B, Z, M, A] 
"1 start" "2 start" [A, B, Z, C, T]
"2 start" "1 start" [Z, B, C, X, A]
"2 start" "2 start" [B, X, C, M, B, C]

并且如果以上情况均不返回,则返回false

在非功能性情况下,这可以通过脏循环逻辑来实现,但是有没有更好的功能性方法来解决此问题?

还要最小化列表的迭代次数。

2 个答案:

答案 0 :(得分:2)

此解决方案仅遍历列表,并在找到解决方案后立即停止。它是尾递归的,因此应该编译成一个简单的循环。

def hasTwoStarts[T](list: List[T]) = {
  @annotation.tailrec
  def loop(l: List[T], startCount: Int, seenB: Boolean): Boolean = l match {
    case _ if startCount == 2 => true
    case Nil => false
    case h :: t => h match {
      case A =>
        loop(t, startCount + 1, seenB)
      case B =>
        loop(t, startCount, true)
      case C if seenB =>
        loop(t, startCount + 1, false)
      case _ =>
        loop(t, startCount, seenB)
    }
  }

  loop(list, 0, false)
}

这是解决该问题的非常具体的方法,如果更改了任何“开始”条件,则需要重新进行处理。

答案 1 :(得分:1)

问题似乎有点含糊(至少比public class Model { private String name; private String type; private String string; public Model(String name, String type, String string) { this.name = name; this.type = type; this.string = string; } } "1 start"的名字更好吗?),您可以使用以下代码片段 em>


从这些实用程序方法开始

"2 start"

写一个给出// Utility methods def endIndexOf1Start(list: List[String], startIndex: Int = 0): Option[Int] = { val firstIndex: Int = list.indexOf("A", from=startIndex) if (firstIndex >= 0) Some(firstIndex) else None } def endIndexOf2Start(list: List[String], startIndex: Int = 0): Option[Int] = { lazy val indexOfB: Int = list.indexOf("B", from=startIndex) lazy val indexOfC: Int = list.indexOf("C", from=indexOfB) if ((indexOfB >= 0) && (indexOfC > indexOfB)) Some(indexOfC) else None } def endIndexOfSomeStart(list: List[String], startIndexOpt: Option[Int] = None): Option[Int] = { val startIndex: Int = startIndexOpt.getOrElse(0) lazy val _endIndexOf1Start: Option[Int] = endIndexOf1Start(list, startIndex) lazy val _endIndexOf2Start: Option[Int] = endIndexOf2Start(list, startIndex) _endIndexOf1Start.orElse(_endIndexOf2Start) } 的方法:是否有2个单独的(不重叠开始

Boolean

提供示例输入

// Final decider method
def containsTwoStarts(list: List[String]): Boolean = {
  lazy val endIndexOfFirstStart: Option[Int] = endIndexOfSomeStart(list)
  lazy val endIndexOfSecondStart: Option[Int] = endIndexOfSomeStart(list, endIndexOfFirstStart)
  (endIndexOfFirstStart.nonEmpty && endIndexOfSecondStart.nonEmpty)
}

这是输入输出示例

// Sample input
val sampleInputs: List[List[String]] = List(
  List("A", "B", "Z", "M", "A"),
  List("A", "B", "Z", "C", "T"),
  List("Z", "B", "C", "X", "A"),
  List("B", "X", "C", "M", "B", "C")
)
// invocation
sampleInputs.map(l => endIndexOf1Start(l, 0))
sampleInputs.map(l => endIndexOf2Start(l, 0))
sampleInputs.map(l => endIndexOfSomeStart(l, None))
sampleInputs.map(containsTwoStarts)