Scala的排序一个列表,根据在另一个

问题描述:

值我有两个IndexedSeqScala的排序一个列表,根据在另一个

works[Work] 
order[Int] 

每个对象工作具有整数值的id字段:Work.id 为了列出有IDS,这是在我们需要整理工作的顺序。就像在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"), 
+0

邮编在一起,排序,然后再解压? – 2015-04-02 16:07:11

+1

听起来奇怪0_o这是如何工作的,究竟是什么? – Ophelia 2015-04-02 16:08:33

+0

当然有一种方法。发布'IndexedSeq''works'和'orders'的样本数据以及您希望输出的样子。 – Brian 2015-04-02 16:08:57

您可以使用字典的是,复杂度为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 - 只用找到的,而不是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)) 

如果你不“T希望在情况异常,如果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)) 
+0

我真的很喜欢第二张照片的样子,让我测试一下:) – Ophelia 2015-04-02 16:29:57

你可能会感兴趣的sortWith方法:

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

只是提到这里的复杂性是关于'O(N * N * logN)> O(N * N)'作为indexOf '是线性的 – dk14 2015-04-02 16:43:22

+0

当然 - 在这种情况下效率低下,但我只想提出'sortWith'方法,并且在很多小的情况下,复杂性不如可读性那么重要! – 2015-04-02 16:49:29

+1

正如我所说,“只是提及”,没有批评:) – dk14 2015-04-02 16:52:34

假设你有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)) 

现在你可以租期,提高通过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)。

您可以从地图上以相同的顺序为Seq[WorkId]转换Seq[Work]Map[WorkId, Work]collect值。

例如:

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")) 
+0

这实际上应该被标记为正确的答案,它超级简单,工作得很好。 – OOPMan 2016-11-08 19:01:49