我需要在数组中找到第一个'\t'
符号。由于我们在scala中没有i++
左右,所以我最终编写了以下内容:
val data: Array[Byte] = //..
var i = 0
while(i < data.length && data{val j = i; i += 1; j} != '\t'){ }
我们能以更整洁的方式重构吗?
答案 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
}
}
或更简洁的版本:
def iterateUntilByte(byte: Byte, array: Array[Byte]): Any = {
array.map(a => if(a != byte) /* do something */) // can be foreach if return type is Unit
}
您可以修改上述代码,以便在找到\t
时执行任何操作,例如if(a == byte) {...} else {...}
(如果您只对\t
条目感兴趣)。
答案 1 :(得分:3)
不要使用var
(如果在时间限制内尽可能;请注意,这总是可行的。)
不要使用return
(从来没有!Read this)。
你也应该永远不要写一个循环。当你第一次开始使用来自命令式语言的Scala时,这似乎很难,但总会有更好的方法。尝试编写循环不是“scala方式”,而不是函数式编程。
您可以使用takeWhile
和foreach
执行某些操作,直到满足某些条件。您可以使用find
获取与某些条件匹配的第一个项目。您可以使用indexOf
。您可以使用zipWithIndex
。您可以使用filter
。您可以使用foldLeft
,collect
,groupBy
或当然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)
}
希望这会有所帮助。如果您需要帮助我们将这些想法扩展到您的实际问题,请告诉我。