gpt4 book ai didi

用于分组的 Scala 集合,同时保持顺序

转载 作者:行者123 更新时间:2023-12-02 03:47:41 25 4
gpt4 key购买 nike

我有这样的东西

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 的 Job 在 workId 为 3 的作业之前出现,因此映射中 a 的条目在 JobId 3 之前具有 JobId 1。

我找不到直接的方法来执行此操作。现在我有:

((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 和 map 产生的额外迭代。

是否有更惯用和简洁的方式使用标准收集方法来执行此操作?

最佳答案

与列表处理的几乎所有问题一样,这可以通过折叠解决!

(for {
job <- jobs.view;
user <- job.users
} yield (job, user)).foldLeft (Map[String, Vector[Int]]()) { case (acc, (a,b)) =>
acc + (b -> (acc.getOrElse(b, Vector()) :+ a.workId))
}

不幸的是,Scala 的类型推断器无法确定初始“Map”的类型,因此您必须明确指定它。

在初始集合上使用 'view' 方法会变得懒惰,并且只会执行一次遍历初始列表。

关于用于分组的 Scala 集合,同时保持顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15943563/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com