scala中的惯用方法,用于模拟/替换重复操作的一元加法

时间:2014-05-27 17:45:34

标签: scala

在支持一元加法的语言中,以及在类似数组的结构中对顺序项执行长列操作的情况下,我可能会创建一个简单的计数器" 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
    )

3 个答案:

答案 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