正在修改将Java模块翻译成Scala并认为这对地图/占位符来说是一个很好的学习练习......有没有办法将这个代码块的本质转化为单个(map?)语句? (这是我迄今为止为Scala-ized版本提出的)
dataProcList foreach (processor => { // #1
val fieldName: String = processor.getWriteColumn // #2
val sqlValue: String = processor.getSqlValue(hashMapOfFieldValuePairs.get(fieldName)) // #3
sqlColumnValuePair += ((fieldName, sqlValue)) // #4
})
简而言之:
这些线路已经扩展以便于阅读;并且可以使用各种映射(例如1& 2)来提取部分,但是有没有办法在使用单个参数时进行操作?感觉就像我应该能够将它压缩到那么远......但是我没有足够的Scala经验与Map -ings /占位符来知道它是否是一个没有结果的努力。
TIA。
(注意:我发现这篇文章的答案是关于Scala地图操作的非常有教育意义的总结:Functional programming, Scala map and fold left)
编辑:我从原始示例中删除了一个.getOrElse()操作,因为我认为这只会分散核心问题。
编辑2:经过一番考虑之后,也许更好的方法来说明我的学习目标是:“如何使用最少的操作来复制此功能。” (我假设它将是地图操作,部分函数等的某种组合。)在这样做的过程中,希望能够更广泛地理解可以在类似情况下使用的Scala类/运算符集。
答案 0 :(得分:1)
我不确定你的意思是“将它压缩成一个单一的陈述”。 您可以定义一个函数,给定一个处理器,返回一对(fieldName,sqlValue)并在地图中使用该函数。
def getColumnValuePair(p:Processor) = {
val fieldName = p.getWriteColumn
fieldName -> p.getSqlValue(hashMapOfFieldValuePairs.get(fieldName))
}
val sqlColumnValuePair = dataProcList.map(getColumnValuePair)
答案 1 :(得分:1)
你可以通过理解来做到这一点(这可能是最常用的方法):
for {
processor <- dataProcList
fieldName = processor.getWriteColumn
fieldValue <- hashMapOfFieldValuePairs.get(fieldName)
} yield (fieldName -> processor.getSqlValue(fieldValue))
这相当于:对于每个处理器,获取写入列,在字段值hashmap中查找(返回一个Option),然后对于该Option中的每个值(一个或零值),yield(粗略) :添加一个不断增长的结果值序列)对fieldName和相应的sqlValue,如果有的话。
请注意,在这种情况下,没有getOrElse调用,因此 - 如果散列映射中没有给定字段名称的条目,则不会为该处理器生成(fieldname,sqlValue)对。最终结果将过滤掉这些值(可能与您之后的语义相匹配或不匹配)。
答案 2 :(得分: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")
)
}
输出:
Original solution: List((writeCol1,sqlValWriteCol1), (writeCol3,sqlValWriteCol3)) New solution: List((writeCol1,sqlValWriteCol1), (writeCol3,sqlValWriteCol3)) New solution #2: List((writeCol1,sqlValWriteCol1), (writeCol3,sqlValWriteCol3))
EDIT1:
我不知道为什么你不想使用for comprehension - 最后它被编译成地图调用...但是如你所愿,我只添加了一个地图调用解决方案(newSolution2
)。
答案 3 :(得分: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))))