0

正在修补将 Java 模块翻译成 Scala 并认为这将是一个很好的地图/占位符学习练习......有没有办法将此代码块的本质翻译成单个(地图?)语句?(这是我迄今为止为 Scala 化版本提出的)

dataProcList foreach (processor => { // #1
  val fieldName: String = processor.getWriteColumn // #2
  val sqlValue: String = processor.getSqlValue(hashMapOfFieldValuePairs.get(fieldName)) // #3
  sqlColumnValuePair += ((fieldName, sqlValue)) // #4
})

简而言之:

  1. 迭代 DataProcessor(s) 的列表
  2. 从每个 DP 中提取一个字符串(称为“Alpha”)
  3. Alphpa 用作(外部定义的)HashMap 的查找键,它获取/返回 SQL 准备的值(称为“Zed”)
  4. 然后将 Alpha 和 Zed 配对并附加到它们自己的 List/Hash/Set/Whatever(称为“sqlColumnValuePair”)

为了便于阅读,这些行已被扩展;并且可以使用各种映射(例如1和2)来提取部分,但是有没有办法使用单个语句来做到这一点?感觉我应该能够把它浓缩到那么远……但我没有足够的 Scala 经验来处理映射/占位符,不知道这是否是徒劳的努力。

TIA。

(注意:我发现这篇文章的答案是关于 Scala 映射操作的非常有教育意义的总结:函数式编程、Scala 映射和左折叠

编辑:我从原始示例中删除了 .getOrElse() 操作,因为我认为这只是对核心问题的干扰。

编辑 2:经过一番考虑,在这里表达我的学习目标的更好方法可能是:“如何使用最少的操作来复制此功能。” (我曾假设这将是映射操作、部分函数等的某种组合。)这样做,希望能够更广泛地了解可在类似情况下使用的 Scala 类/运算符集。

4

4 回答 4

1

You could do this with a for comprehension (and this is probably the most idiomatic way to do it):

for {
  processor <- dataProcList
  fieldName = processor.getWriteColumn
  fieldValue <- hashMapOfFieldValuePairs.get(fieldName)
} yield (fieldName -> processor.getSqlValue(fieldValue))

This amounts to: for each processor, get the write column, look this up in the field-value hashmap (get back an Option), then for each value in that Option (either one or zero values), yield (roughly: add to a growing sequence of result values) the pair fieldName and corresponding sqlValue, if any.

Note that in this case, there is no getOrElse call, as such - if there isn't an entry in the hash map for a given field name, then no (fieldname, sqlValue) pair will be generated for that processor. The final result will have those values filtered out (which may or may not match the semantics you are after).

于 2013-08-16T17:26:46.167 回答
1

像这样使用地图怎么样:

dataProcList.map( x => 
  ( x.getWriteColumn -> x.getSqlValue(hashMapOfFieldValuePairs.get(x.getWriteColumn)) ) 
)

甚至这个,如果你不喜欢调用 getWriteColumn 两次:

dataProcList.map(x=>(x,x.getWriteColumn)).map(y=>(y._2->y._1.getSqlValue(hashMapOfFieldValuePairs.get(y._2)))) 
于 2013-08-17T01:22:14.163 回答
1

这是我测试过的解决方案。它不处理任何故障(与原始解决方案相同)。

object ListStuff extends App {

  import ListStuffMocks._

  // original solution (slightly modified to actually compile and run)
  var sqlColumnValuePair = List[(String, String)]()
  dataProcList foreach (processor => {
    val fieldName: String = processor.getWriteColumn
    val sqlValue: String = processor.getSqlValue(hashMapOfFieldValuePairs.get(fieldName).get)
    sqlColumnValuePair :+= ((fieldName, sqlValue))
  })
  val originalSolution = sqlColumnValuePair

  // IMO most readable solution
  val newSolution = for {
    processor <- dataProcList
    fieldName = processor.getWriteColumn
    sqlValue = processor.getSqlValue(hashMapOfFieldValuePairs.get(fieldName).get)
  } yield (fieldName, sqlValue)

  // requested map-solution
  val newSolution2 = dataProcList.map(
    (p) => {
      val fieldName = p.getWriteColumn
      val sqlValue = p.getSqlValue(hashMapOfFieldValuePairs.get(fieldName).get)
      (fieldName, sqlValue)
    }
  )

  println(s"Original solution: $originalSolution")
  println(s"New solution:      $newSolution")
  println(s"New solution #2:   $newSolution2")
}

object ListStuffMocks {

  object DataProcessor {
    val db = Map(
      "valWriteCol1" -> "sqlValWriteCol1",
      "valWriteCol2" -> "sqlValWriteCol2",
      "valWriteCol3" -> "sqlValWriteCol3"
    )
  }

  class DataProcessor(writeColumn: String) {
    def getWriteColumn = writeColumn

    def getSqlValue(field: String): String = DataProcessor.db.get(field).get
  }

  val hashMapOfFieldValuePairs = Map(
    "writeCol1" -> "valWriteCol1",
    "writeCol2" -> "valWriteCol2",
    "writeCol3" -> "valWriteCol3"
  )
  val dataProcList = List(
    new DataProcessor("writeCol1"),
    new DataProcessor("writeCol3")
  )
}

输出:

原始解决方案: List((writeCol1,sqlValWriteCol1), (writeCol3,sqlValWriteCol3))  
新解决方案: List((writeCol1,sqlValWriteCol1), (writeCol3,sqlValWriteCol3))  
新解决方案 #2: List((writeCol1,sqlValWriteCol1), (writeCol3,sqlValWriteCol3))

EDIT1:
我不知道你为什么不想使用 for comprehension - 最后它被编译到地图调用中......但是如你所愿,我添加了一个仅使用一个地图调用(newSolution2)的解决方案。

于 2013-08-16T17:40:40.813 回答
1

我不太确定您所说的“将其压缩为单个语句”是什么意思。您可以定义一个函数,给定一个处理器,返回一对 (fieldName, sqlValue) 并在映射中使用该函数。

def getColumnValuePair(p:Processor) = { 
  val fieldName = p.getWriteColumn
  fieldName -> p.getSqlValue(hashMapOfFieldValuePairs.get(fieldName))
}

val sqlColumnValuePair = dataProcList.map(getColumnValuePair)
于 2013-08-16T17:25:18.250 回答