我有这样的东西
case class Job(workId: Int, users: List[String])
val jobs = IndexedSeq(Job(1, List("a", "b")), Job(2, List("b", "c")), Job(3, List("a", "c" )), Job(4, List("d", "b")))
我想将其转换为:
Map(c -> Vector(2, 3), a -> Vector(1, 3), d -> Vector(4), b -> Vector(1, 2, 4))
我基本上想保持原来的顺序中的 Job.workId 的顺序。因此,由于 workId 为 1 的作业位于 workId 为 3 的作业之前,因此地图中的 a 条目的 JobId 1 在 JobId 3 之前。
我找不到这样做的直接方法。现在我有:
((for (job <- jobs;
user <- job.users)
yield { (user, job.work) }) groupBy { tuple => tuple._1 }) map { tuple => (tuple._1 -> (tuple._2 map { _._2 })) }
这首先创建:
Map(c -> Vector((c,2), (c,3)), a -> Vector((a,1), (a,3)), d -> Vector((d,4)), b -> Vector((b,1), (b,2), (b,4)))
然后将其转换为:
Map(c -> Vector(2, 3), a -> Vector(1, 3), d -> Vector(4), b -> Vector(1, 2, 4))
这似乎相当冗长。我想知道是否有更简单的方法可以在保留订单的同时做到这一点。我也不喜欢它需要多次迭代初始序列。
我有另一个更长的解决方案:
val mapping = scala.collection.mutable.Map[String, IndexedSeq[Int]]()
for (job <- jobs;
user <- job.users)
yield{
if (mapping.contains(user)) {
val entry = mapping(user)
mapping.put(user, entry :+ job.work)
} else {
mapping += user -> mutable.IndexedSeq(job.work)
}
}
现在的映射是:
Map(c -> ArrayBuffer(2, 3), a -> ArrayBuffer(1, 3), d -> ArrayBuffer(4), b -> ArrayBuffer(1, 2, 4))
这共享了初始的理解,但不需要使用 groupBy 然后映射的额外迭代。
使用标准收集方法是否有更惯用和简洁的方法?