将一系列Scala映射操作推送到单独的列表中

时间:2013-08-16 16:35:41

标签: scala map placeholder

正在修改将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. 迭代DataProcessor列表
  2. 从每个DP中提取一个字符串(称之为“Alpha”)
  3. Alphpa用作(外部定义的)HashMap的查找键,它获取/返回SQL-prep'd值(称之为“Zed”)
  4. 然后将Alpha和Zed配对并附加到他们自己的List / Hash / Set / Whatever(称为“sqlColumnValuePair”)
  5. 这些线路已经扩展以便于阅读;并且可以使用各种映射(例如1& 2)来提取部分,但是有没有办法在使用单个参数时进行操作?感觉就像我应该能够将它压缩到那么远......但是我没有足够的Scala经验与Map -ings /占位符来知道它是否是一个没有结果的努力。

    TIA。

    (注意:我发现这篇文章的答案是关于Scala地图操作的非常有教育意义的总结:Functional programming, Scala map and fold left

    编辑:我从原始示例中删除了一个.getOrElse()操作,因为我认为这只会分散核心问题。

    编辑2:经过一番考虑之后,也许更好的方法来说明我的学习目标是:“如何使用最少的操作来复制此功能。” (我假设它将是地图操作,部分函数等的某种组合。)在这样做的过程中,希望能够更广泛地理解可以在类似情况下使用的Scala类/运算符集。

4 个答案:

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