在支持一元加法的语言中,以及在类似数组的结构中对顺序项执行长列操作的情况下,我可能会创建一个简单的计数器" int counter = 0;"并执行以下操作:
someOperation(array[counter++]);
nextOperation(array[counter++]);
subsequentOperation(array[counter++]);
.. etc
scala中实现类似行为的惯用方法是什么 - 即避免需要硬编码的输入数组索引?下面是一个具体示例:一个简单的记录解析器方法,它将制表符分隔的调用详细信息转换为Call对象。不知道有什么更好的方法我做了一个丑陋的东西放入AtomicInteger。但是这样做的可行方法是什么?
注意:我们不能简单地在这里进行集体操作,因为有些操作 列需要" .toInt"处理和其他人没有。
def parseStringToCall(text: String) = {
val toks = text.split('\t')
val ix = new AtomicInteger(0)
new CallUpdate(
toks(ix.getAndIncrement), // callDate
toks(ix.getAndIncrement), // calledNumber
toks(ix.getAndIncrement), // callingNumbe
toks(ix.getAndIncrement), // cellTowersVi
toks(ix.getAndIncrement), // direction
toks(ix.getAndIncrement), // iMSI
toks(ix.getAndIncrement), // manufacturer
toks(ix.getAndIncrement), // phoneType
toks(ix.getAndIncrement), // reasonforDro
toks(ix.getAndIncrement).toInt, // weeknum
toks(ix.getAndIncrement), // firstCellTow
toks(ix.getAndIncrement), // lastCellTowe
toks(ix.getAndIncrement).toInt, // calls
toks(ix.getAndIncrement), // distinctCell
toks(ix.getAndIncrement), // droppedCall
toks(ix.getAndIncrement).toInt, // handovers
toks(ix.getAndIncrement).toInt, // setupTime
toks(ix.getAndIncrement).toInt // talkTime
)
答案 0 :(得分:3)
也许您无法使用索引访问数组,但使用模式匹配。
鉴于您将呼叫更新定义为案例类(我省略了一些字段)
case class CallUpdate(
callDate: String,
calledNumber: String,
callingNumber: String,
cellTowersVi: String,
direction: String,
iMSI: String,
manufacturer: String,
phoneType: String,
reasonforDro: String,
weekNum: Int,
firstCellTow: String,
calls: Int
)
你可以像这样写parseStringToCall
def parseStringToCall(text: String) = text.split('\t') match {
case Array (
callDate, calledNumber, callingNumber, cellTowersVi, direction, iMSI, manufacturer,
phoneType, reasonforDro, weekNumString, firstCellTow, callsString
) => CallUpdate(callDate, calledNumber, callingNumber, cellTowersVi, direction, iMSI, manufacturer,
phoneType, reasonforDro, weekNumString.toInt, firstCellTow, callsString.toInt)
}
此外,使用此方法,您可以通过添加通配符来处理不匹配的行,例如返回None
。
PS。也许您可以考虑将CallUpdate
拆分为较小的专用对象。
答案 1 :(得分:3)
你正在迫切地解决这个问题。惯用语Scala更多的是关于函数式编程。你必须习惯将函数视为值并利用它的力量。
您的问题可以通过以下功能解决:
toks
// Get a lazy wrapper around `toks`, so that all the subsequent
// operations will be done in just a single traversal:
.view
// Pair each item of `toks` up with an according operation:
.zip(List(someOperation(_), nextOperation(_), subsequentOperation(_)))
// Traverse thru those pairs, applying the operations:
.foreach{ case (t, f) => f(t) }
必须注意,操作应该是String => Unit
类型。
答案 2 :(得分:1)
为了后代搜索标题上的问题,这是Scala中postIncrement的潜在实现:
class Counter(start:Int = 0) {
var current = start
def ++ : Int = {val x=current; current +=1 ; x}
}
repl> val i = new Counter
repl> i: Counter = Counter@2a01a9f2
repl> i++
repl> res26: Int = 0
repl> i++
repl> res27: Int = 1
现在,要解决问题正文中的特定用例:即迭代数组而不必处理索引,可能最直接的方法是使用迭代器:
val args = Array("arguments","with","ints","23","46")
val iter = args.iterator
val res = CallUpdate(iter.next, iter.next, iter.next, iter.next.toInt, iter.next.toInt)
这样可以清晰地解决索引访问问题。
我们可以做得更好吗?大概。我们可以更优雅的方式解决类型转换问题。 为此,我们定义了一个简单的标记类型和隐式转换,以避免必须处理那些toInt调用。这当然可以扩展到其他类型,如Date,Long,......
case class Param(value:String)
object Param {
implicit def paramToString(p:Param):String = p.value
implicit def paramToInt(p:Param):Int = p.value.toInt
}
我们可以这样做:
val args = Array("arguments","with","ints","23","46")
val params = args.map(elem => Param(elem))
val iter = params.iterator
val res = CallUpdate(iter.next, iter.next, iter.next, iter.next, iter.next)
如果你想要一个令人兴奋的解决方案,我建议你阅读:applying-an-argument-list-to-curried-function