【问题标题】:How to create an lookup Map in Scala如何在 Scala 中创建查找映射
【发布时间】:2011-10-13 00:11:47
【问题描述】:
虽然我知道有几种方法可以做到这一点,但我最感兴趣的是找到最惯用和最实用的 Scala 方法。
举个例子:
case class User(id: String)
val users = List(User("1"), User("2"), User("3"), User("4"))
创建 user.id 的不可变查找 Map 的最佳方法是什么 -> 用户以便我可以通过 user.id 执行快速查找。
在 Java 中,我可能会使用 Google-Collection 的 Maps.uniqueIndex,尽管我不太关心它的独特属性。
【问题讨论】:
标签:
scala
collections
functional-programming
【解决方案1】:
您可以将用户保存在列表中并使用 list.find:
users.find{_.id == "3"} //returns Option[User], either Some(User("3")) or None if no such user
或者如果您想使用 Map,请将用户列表映射到 2 元组列表,然后使用 toMap 方法:
val umap = users.map{u => (u.id, u)}.toMap
这将返回一个不可变的 Map[String, User],然后你可以使用
umap contains "1" //return true
或
umap.get("1") //returns Some(User("1"))
【解决方案2】:
如果您确定所有 ID 都是唯一的,那么规范的方式是
users.map(u => (u.id, u)).toMap
正如@Dan Simon 所说。但是,如果您不确定所有 ID 都是唯一的,那么规范的方法是:
users.groupBy(_.id)
这将生成从用户 ID 到共享该 ID 的用户的列表的映射。
因此,有另一种不完全规范的方式来生成从 ID 到单个用户的地图:
users.groupBy(_.id).mapValues(_.head)
对于想要避免创建列表映射的中间步骤或随后转换为映射的列表的专家用户,有一个方便的 scala.collecion.breakOut 方法可以构建您想要的类型,如果有一个简单的方法来做到这一点。不过,它需要知道类型,所以这可以解决问题:
users.map(u => (u.id,u))(collection.breakOut): Map[String,User]
(您也可以分配给指定类型的 var 或 val。)
【解决方案3】:
将 List 转换为 Map 并将其用作函数:
case class User(id: String)
val users = List(User("1"), User("2"), User("3"))
val usersMap = users map { case user @ User(id) => id -> user } .toMap
usersMap("1") // Some(User("1"))
usersMap("0") // None
【解决方案4】:
如果您想使用数字索引:
scala> users.map (u=> u.id.toInt -> u).toMap
res18: scala.collection.immutable.Map[Int,User] =
Map((1,User(1)), (2,User(2)), (3,User(3)))
【解决方案5】:
Maps 也是函数,它们的 apply 方法提供对与特定键关联的值的访问(或为未知键引发 NoSuchElementException),因此这使得查找语法非常简洁。遵循 Dan Simon 的回答并使用更具语义意义的名称:
scala> val Users = users map {u => (u.id, u)} toMap
Users: scala.collection.immutable.Map[String,User] = Map((1,User(1)), (2,User(2)), (3,User(3)))
然后提供以下查找语法:
scala> val user2 = Users("2")
user2: User = User(2)