从数据库表中填充Scala不可变映射

Ral*_*lph 4 functional-programming scala

我有一个SQL数据库表,具有以下结构:

create table category_value (
  category varchar(25),
  property varchar(25)
);
Run Code Online (Sandbox Code Playgroud)

我想将其读入Scala Map[String, Set[String]],其中地图中的每个条目都是同一类别中所有属性值的集合.我想以"功能"样式进行,没有可变数据(数据库结果集除外).

继Clojure loop构造之后,我提出了以下内容:

def fillMap(statement: java.sql.Statement): Map[String, Set[String]] = {
    val resultSet = statement.executeQuery("select category, property from category_value")

    @tailrec
    def loop(m: Map[String, Set[String]]): Map[String, Set[String]] = {
      if (resultSet.next) {
        val category = resultSet.getString("category")
        val property = resultSet.getString("property")
        loop(m + (category -> m.getOrElse(category, Set.empty)))
      } else m
    }

    loop(Map.empty)
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法来做到这一点,而不使用可变数据结构?

Deb*_*ski 8

如果你愿意,你可以尝试一下

def fillMap(statement: java.sql.Statement): Map[String, Set[String]] = {
  val resultSet = statement.executeQuery("select category, property from category_value")
  Iterator.continually((resultSet, resultSet.next)).takeWhile(_._2).map(_._1).map{ res =>
    val category = res.getString("category")
    val property = res.getString("property")
    (category, property)
  }.toIterable.groupBy(_._1).mapValues(_.map(_._2).toSet)
}
Run Code Online (Sandbox Code Playgroud)

未经测试,因为我没有适当的sql.Statement.而这groupBy部分可能需要更多的爱看起来不错.

编辑:添加了请求的更改.

  • 在`groupBy`之前,你需要放一个`toIterable`,因为`Iterators`没有`groupBy`函数(它们只实现可以作为派生迭代器返回的东西).另外,你可以在`groupBy`之后使用`mapValues`来简化一些事情. (3认同)

Ken*_*oom 5

这个问题有两个部分.

将数据从数据库中取出并放入行列表中.

我会使用Spring SimpleJdbcOperations进行数据库访问,这样即使在幕后更改ResultSet,事物也至少会显示功能.

首先,一些简单的转换让我们使用闭包来映射每一行:

implicit def rowMapper[T<:AnyRef](func: (ResultSet)=>T) = 
  new ParameterizedRowMapper[T]{
    override def mapRow(rs:ResultSet, row:Int):T = func(rs)
  }
Run Code Online (Sandbox Code Playgroud)

然后让我们定义一个数据结构来存储结果.(你可以使用一个元组,但是定义我自己的case类有利于对事物的名称稍微清楚一些.)

case class CategoryValue(category:String, property:String)
Run Code Online (Sandbox Code Playgroud)

现在从数据库中选择

val db:SimpleJdbcOperations = //get this somehow
val resultList:java.util.List[CategoryValue] = 
  db.query("select category, property from category_value",
    { rs:ResultSet => CategoryValue(rs.getString(1),rs.getString(2)) } )
Run Code Online (Sandbox Code Playgroud)

将行列表中的数据转换为您实际需要的格式

import scala.collection.JavaConversions._
val result:Map[String,Set[String]] =
  resultList.groupBy(_.category).mapValues(_.map(_.property).toSet)
Run Code Online (Sandbox Code Playgroud)

(你可以省略类型注释.我已经将它们包含在内,以便明确发生了什么.)