如何在Scala中创建查找映射

时间:2011-07-25 23:21:56

标签: scala collections functional-programming

虽然我知道有几种方法可以做到这一点,但我最感兴趣的是找到最具惯用性和功能性的Scala方法。

给出以下陈腐的例子:

case class User(id: String)
val users = List(User("1"), User("2"), User("3"), User("4")) 

创建不可变查找地图的最佳方法是user.id - >用户,以便我可以通过user.id执行快速查找。

在Java中,我可能会使用Google-Collection的Maps.uniqueIndex,尽管我不太关注它的独特属性。

5 个答案:

答案 0 :(得分:5)

您可以将用户保留在列表中并使用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"))

答案 1 :(得分:4)

如果您确定所有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。)

答案 2 :(得分:1)

将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

答案 3 :(得分:0)

如果您想使用数字索引:

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

答案 4 :(得分:0)

映射也是函数,它们的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)