Scala根据另一个列表中的值对一个列表进行排序

时间:2015-04-02 16:04:59

标签: list scala

我有两个IndexedSeq

works[Work]
order[Int]

每个对象Work都有一个带整数值的id字段:Work.id 在订单列表中有一些ID,它们按照我们需要整理工作的顺序排列。就像,在位置0中有第一个id,所以我们需要在工作数组中找到与此对应的id的工作,并将其放在0位置,依此类推。 有没有办法用scala做这个而不经过两个循环?就像,一些优雅的方式? 一些伪数据,例如:

order = 33, 22, 11, 55

works = (33, "some text"), (55, "eeeee"), (22, "fdsfs"), (11, "fdsffds")

排序后:

order = 33, 22, 11, 55

works = (33, "some text"),(22, "fdsfs"),  (11, "fdsffds"), (55, "eeeee"),

4 个答案:

答案 0 :(得分:7)

你可以使用字典,这里的复杂度是O(N)(两个嵌套循环的N * N比较好):

scala> val order = List(33, 22, 11, 55)
order: List[Int] = List(33, 22, 11, 55)

scala> val works = List((33, "some text"), (55, "eeeee"), (22, "fdsfs"), (11, "fdsffds"))
works: List[(Int, String)] = List((33,some text), (55,eeeee), (22,fdsfs), (11,fdsffds))

scala> val worksMap = works.toMap
worksMap: scala.collection.immutable.Map[Int,String] = Map(33 -> some text, 55 -> eeeee, 22 -> fdsfs, 11 -> fdsffds)

scala> val newWorks = order zip order.map(worksMap)
newWorks: List[(Int, String)] = List((33,some text), (22,fdsfs), (11,fdsffds), (55,eeeee))

如果您的实体不仅仅是元组:

scala> val worksMap = (works map (_._1) zip works).toMap //any other key extraction, like `_.myKey` may be applied instead of `_._1`
worksMap: scala.collection.immutable.Map[Int,(Int, String)] = Map(33 -> (33,some text), 55 -> (55,eeeee), 22 -> (22,fdsfs), 11 -> (11,fdsffds))

scala> order.map(worksMap)
res13: List[(Int, String)] = List((33,some text), (22,fdsfs), (11,fdsffds), (55,eeeee))

如果你不想花费Map的内存 - 只需使用find而不是Map.apply(但它会是O(N * N),所以它是较慢):

scala> val newWorks = order.map(x => works.find(_._1 == x).get)
newWorks: List[(Int, String)] = List((33,some text), (22,fdsfs), (11,fdsffds), (55,eeeee))

如果order不包含您的密钥,如果您不想要例外,则可以使用flatMap

scala> val newWorks = order.flatMap(x => works.find(_._1 == x))
newWorks: List[(Int, String)] = List((33,some text), (22,fdsfs), (11,fdsffds), (55,eeeee))

scala> order.flatMap(worksMap.get)
res15: List[(Int, String)] = List((33,some text), (22,fdsfs), (11,fdsffds), (55,eeeee))

答案 1 :(得分:5)

您可能对sortWith方法感兴趣:

works.sortWith((a, b) => order.indexOf(a._1) < order.indexOf(b._1))

答案 2 :(得分:3)

您可以按照与Seq[Work]相同的顺序将Map[WorkId, Work]转换为collectSeq[WorkId]地图中的值。

例如:

case class Work(id: Int, text: String)
// defined class Work

val order = Seq(33, 22, 11, 55)
// order: Seq[Int] = List(33, 22, 11, 55)

val works = Seq(Work(33, "some text"), Work(55, "eeeee"), Work(22, "fdsfs"), Work(11, "fdsffds"))
// works: Seq[Work] = List(Work(33, "some text"), Work(55, "eeeee"), Work(22, "fdsfs"), Work(11, "fdsffds"))

val workMap = works.map(work => work.id -> work).toMap
// workMap: Map[Int, Work] = Map(33 -> Work(33, "some text"), 55 -> Work(55, "eeeee"), 22 -> Work(22, "fdsfs"), 11 -> Work(11, "fdsffds"))

order.collect(workMap)
// res14: Seq[Work] = List(Work(33, "some text"), Work(22, "fdsfs"), Work(11, "fdsffds"), Work(55, "eeeee"))

这与其他答案类似,但使用的是collect,因为Map[A, B]也是PartialFunction[A, B]

但是,上述解决方案假设工作ID是唯一的。

如果工作ID不是唯一的,您可以使用groupByflatMap

val works = Seq(Work(33, "a"), Work(34, "b"), Work(33, "c"), Work(35, "d"))
// works: Seq[Work] = List(Work(33, "a"), Work(34, "b"), Work(33, "c"), Work(35, "d"))

val worksMap = works.groupBy(_.id)
//worksMap: Map[Int, Seq[Work]] = Map(35 -> List(Work(35, "d")), 34 -> List(Work(34, "b")), 33 -> List(Work(33, "a"), Work(33, "c")))

val order = Seq(35, 34, 33)
//order: Seq[Int] = List(35, 34, 33)

order.flatMap(id => worksMap.getOrElse(id, Seq.empty))
// res23: Seq[Work] = List(Work(35, "d"), Work(34, "b"), Work(33, "a"), Work(33, "c"))

答案 3 :(得分:2)

假设您的数据位于List,您可以执行以下操作:

scala> val order = List(33, 22, 11, 55)
order: List[Int] = List(33, 22, 11, 55)

scala> val works = List((33, "some text"), (55, "eeeee"), (22, "fdsfs"), (11, "fdsffds"))
works: List[(Int, String)] = List((33,some text), (55,eeeee), (22,fdsfs), (11,fdsffds))

scala> val sortedWorks = order.flatMap( id => works.find(x => x._1 == id ))
sortedWorks: List[(Int, String)] = List((33,some text), (22,fdsfs), (11,fdsffds), (55,eeeee))

现在你可以使用Map来优化按ID查找工作的部分,这样就可以了:

scala> val worksMap = works.toMap
worksMap: scala.collection.immutable.Map[Int,String] = Map(33 -> some text, 55 -> eeeee, 22 -> fdsfs, 11 -> fdsffds)

scala> val sortedWorks = order.flatMap( id => worksMap.get(id))
sortedWorks: List[String] = List(some text, fdsfs, fdsffds, eeeee)

性能取决于查找。在这种情况下,由于HashMap,它是摊销的O(N)。