例如,假設我有有沒有辦法在Scala for循環中處理最後一種情況?
for (line <- myData) {
println("}, {")
}
是否有一種方式來獲得最後一行打印
println("}")
例如,假設我有有沒有辦法在Scala for循環中處理最後一種情況?
for (line <- myData) {
println("}, {")
}
是否有一種方式來獲得最後一行打印
println("}")
在進一步討論之前,我'd建議你避免println
爲理解。它有時可以用於追蹤集合中間發生的錯誤,但否則會導致代碼難以重構和測試。
更一般地說,如果您可以限制哪裏發生任何副作用,生活通常會變得更容易。因此,而不是:
for (line <- myData) {
println("}, {")
}
你可以寫:
val lines = for (line <- myData) yield "}, {"
println(lines mkString "\n")
我還要在這裏採取的猜測,你想在輸出的每一行的內容!
val lines = for (line <- myData) yield (line + "}, {")
println(lines mkString "\n")
雖然你會是好還是如果你只是使用mkString
直接 - 這就是它是!
val lines = myData.mkString("{", "\n}, {", "}")
println(lines)
注意我們如何首先生產String
,然後再打印在一個單一的操作。這種方法可以很容易地分解成單獨的方法,並用於在您的類上實現toString
,或者在測試中檢查生成的String。
您可以採取TraversableOnce
特質作爲例子的addString功能。
def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = {
var first = true
b append start
for (x <- self) {
if (first) {
b append x
first = false
} else {
b append sep
b append x
}
}
b append end
b
}
在你的情況下,隔膜是}, {
和到底是}
+1。很高興看到它是如何在標準庫中完成的。 –
可以重構代碼趁內置mkString
?
scala> List(1, 2, 3).mkString("{", "}, {", "}")
res1: String = {1}, {2}, {3}
如果你不希望使用內置mkString功能,你可以像
for (line <- lines)
if (line == lines.last) println("last")
else println(line)
UPDATE:正如在評論中提到didierd,該解決方案是錯誤的,因爲最後一個值可以發生好幾次,他在他的answer中提供了更好的解決方案。
這是罰款Vectors
,因爲last
功能以「有效恆定的時間」對他們來說,作爲Lists
,它需要線性時間,所以你可以使用模式匹配
@tailrec
def printLines[A](l: List[A]) {
l match {
case Nil =>
case x :: Nil => println("last")
case x :: xs => println(x); printLines(xs)
}
}
遞歸解決方案很好。除非你知道最後一個元素的值不在別的地方,否則用== lines.last的那個是錯誤的。 –
@didierd謝謝,我錯過了。我在答案中指出了錯誤。 – 4e6
我試過用'eq'而不是'==',它仍然不起作用 - 字符串必須緩存,這有點痛苦 –
我完全同意之前所說的關於使用mkstring
,並區分第一次迭代而不是最後一次迭代。你仍然需要區分最後,斯卡拉集合有一個init
方法,它會返回除最後一個元素外的所有元素。 所以你可以做
for(x <- coll.init) workOnNonLast(x)
workOnLast(coll.last)
(init
和last
是排序的頭部和尾部的反面,這是第一個和所有,但第一個)。但是請注意,根據結構不同,它們可能會很昂貴。在Vector
,他們都快。在List
上,雖然頭部和尾部基本上是空閒的,但是init
和last
在列表長度上都是線性的。 headOption
和lastOption
可以幫助你時,集合可能是空的,由
for (x <- coll.lastOption) workOnLast(x)
其他的答案是理所當然指出mkString
更換workOnlast
,以及數據的正常量我也使用它。
但是,mkString
通過StringBuilder
構建(累積)最終結果內存。這並不總是令人滿意的,這取決於我們擁有的數據量。在這種情況下,如果我們想要的只是「打印」,我們不需要先建立大的結果(也許我們甚至想避免這種情況)。
考慮這個輔助函數的實現:
def forEachIsLast[A](iterator: Iterator[A])(operation: (A, Boolean) => Unit): Unit = {
while(iterator.hasNext) {
val element = iterator.next()
val isLast = !iterator.hasNext // if there is no "next", this is the last one
operation(element, isLast)
}
}
它遍歷所有元素,並調用operation
傳遞每個元件又與一個布爾值。如果傳遞的元素是最後一個,則值爲true
。
在你的情況下,它可以像這樣使用:
forEachIsLast(myData) { (line, isLast) =>
if(isLast)
println("}")
else
println("}, {")
}
我們有以下的優點在這裏:
或者稍微優雅些,也許:'forEachIsLast'可以是'val it = seq。toIterator it.foreach {operation(_,it.hasNext)}' –
非常感謝@TheArchetypalPaul!根據您的建議編輯我的答案以使用實現。 –
正如@ Nicolas的答案已經指出的那樣,如果您可以重構所需的行爲以針對* first *迭代採取不同的行爲,而不是最後一個。識別第一次迭代是微不足道的。 –
+1使用scala –