由于我们不能做i ++,如何编码看起来更整洁

时间:2018-06-14 12:18:18

标签: scala int

我需要在数组中找到第一个'\t'符号。由于我们在scala中没有i++左右,所以我最终编写了以下内容:

val data: Array[Byte] = //..
var i = 0
while(i < data.length && data{val j = i; i += 1; j} != '\t'){ }

我们能以更整洁的方式重构吗?

2 个答案:

答案 0 :(得分:4)

如果你想在满足条件之前做一些事情,你可能最好分开while和for循环。在while循环声明中声明一个for循环是很丑陋的,当它变得更复杂时可能是不可预测的。

此外, 不使用var 。最好的做法是在使用Scala时尽可能保持所有内容不变。

这样的技术可以完成这项工作:

def iterateUntilByte(byte: Byte, array: Array[Byte]): Any = {
  for(i <- array.indices) {
    if(array(i) != byte) /* do something */ else return
  }
}

[ScalaFiddle]

或更简洁的版本:

def iterateUntilByte(byte: Byte, array: Array[Byte]): Any = {
  array.map(a => if(a != byte) /* do something */) // can be foreach if return type is Unit
}

[ScalaFiddle]

您可以修改上述代码,以便在找到\t时执行任何操作,例如if(a == byte) {...} else {...}(如果您只对\t条目感兴趣)。

答案 1 :(得分:3)

不要使用var(如果在时间限制内尽可能;请注意,这总是可行的。)

不要使用return(从来没有!Read this)。

你也应该永远不要写一个循环。当你第一次开始使用来自命令式语言的Scala时,这似乎很难,但总会有更好的方法。尝试编写循环不是“scala方式”,而不是函数式编程。

您可以使用takeWhileforeach执行某些操作,直到满足某些条件。您可以使用find获取与某些条件匹配的第一个项目。您可以使用indexOf。您可以使用zipWithIndex。您可以使用filter。您可以使用foldLeftcollectgroupBy或当然map。您可以使用这些的复杂组合。您可以使用递归来“早退”。你不需要“写一个循环”。

您的原始问题似乎是一个XY问题,但看起来val i = data.indexOf('\t')会这样做,除非数据不包含'\t',否则它将是-1。更多想法;

val i = data.indexOf('\t') match {
  case -1 => data.length-1
  case n => n
}

val i = Some(data.indexOf('\t')).filterNot(_ == -1).getOrElse(data.length-1)

def i2(data: Array[Byte]): Array[Byte] = data.takeWhile(_ != '\t')

def printUpToTab(data: Array[Byte]): Unit = i2(data).foreach(println)

// Warning: obtaining the index of something is not usually necessary.
//  Step back and consider a cleaner solution.
def tabIndices(data: Array[Byte]): List[Int] = data.zipWithIndex.collect {
  case ('\t', n) =>
    println(s"Found a tab at $n")
    n
}.toList

// does a list contain less than N tab characters? Simple solution:
def containsLessThanNtabs(data: List[Byte], n: Int): Boolean =
  data.count(_ == '\t') < n

// This version will "return early" when N tabs are found,
//  not counting through the entire list.
// This could be more efficient for very long lists.
// You must have a `List` to use the `::` construct.
def recursiveVersion(data: List[Byte], n: Int): Boolean = {
  def recurse(bytes: List[Byte], count: Int): Boolean = 
    if (count >= n) false
    else {
      bytes match {
        case Nil => true
        case '\t' :: tail => recurse(tail, count+1)
        case _ :: tail => recurse(tail, count)
      }
    }

  recurse(data, 0)
}

希望这会有所帮助。如果您需要帮助我们将这些想法扩展到您的实际问题,请告诉我。