基于另一个列表的顺序的列表的插入顺序

时间:2014-03-07 22:28:02

标签: list scala data-structures functional-programming akka

我在Scala中有一个排序问题,我当然可以用蛮力解决,但我希望有一个更聪明/更优雅的解决方案。假设我有一个没有特定顺序的字符串列表:

val keys = List("john", "jill", "ganesh", "wei", "bruce", "123", "Pantera")

然后随机地,我随机收到这些键的值(完全公开,我在akka演员中遇到这个问题,所以事件不按顺序排列):

def receive:Receive = {
  case Value(key, otherStuff) => // key is an element in keys ...

我希望将这些结果存储在List中,其中Value个对象的显示顺序与key列表中的keys字段的顺序相同。例如,在收到前两条Value消息后,我可能会收到此列表:

List(Value("ganesh", stuff1), Value("bruce", stuff2))

ganesh出现在bruce之前仅仅是因为他出现在keys列表的前面。收到第三条消息后,我应按照keys建立的顺序将其插入此列表中的正确位置。例如,在收到wei时,我应该将他插入中间:

List(Value("ganesh", stuff1), Value("wei", stuff3), Value("bruce", stuff2))

在此过程中的任何时候,我的列表可能不完整,但按预期顺序排列。由于密钥对我的Value数据是多余的,因此我会在值列表完成后将它们丢弃。

告诉我你有什么!

2 个答案:

答案 0 :(得分:3)

我认为你不希望性能低于O(n log n)。所以:

val order = keys.zipWithIndex.toMap
var part = collection.immutable.TreeSet.empty[Value](
  math.Ordering.by(v => order(v.key))
)

然后你只需添加你的物品。

scala> part = part + Value("ganesh", 0.1)
part: scala.collection.immutable.TreeSet[Value] = 
  TreeSet(Value(ganesh,0.1))

scala> part = part + Value("bruce", 0.2)
part: scala.collection.immutable.TreeSet[Value] =
  TreeSet(Value(ganesh,0.1), Value(bruce,0.2))

scala> part = part + Value("wei", 0.3)
part: scala.collection.immutable.TreeSet[Value] = 
  TreeSet(Value(ganesh,0.1), Value(wei,0.3), Value(bruce,0.2))

完成后,您可.toList。在构建它时,您可能不希望这样做,因为以随机顺序更新列表以使其处于所需的排序顺序是必须的O(n^2)成本。


编辑:以七个项目为例,我的解决方案大约是Jean-Philippe的1/3。对于25个项目,它是时间的十分之一。 200的1/30(这是我机器上6 ms和0.2 ms之间的差异)。

答案 1 :(得分:1)

如果您可以使用ListMap而不是元组列表来存储他们收集的值,那么这可能会有效。 ListMap保留了插入顺序。

class MyActor(keys: List[String]) extends Actor {

  def initial(values: ListMap[String, Option[Value]]): Receive = {
    case v @ Value(key, otherStuff) =>
      if(values.forall(_._2.isDefined))
        context.become(valuesReceived(values.updated(key, Some(v)).collect { case (_, Some(v)) => v))
      else
        context.become(initial(keys, values.updated(key, Some(v))))
  }

  def valuesReceived(values: Seq[Value]): Receive = { } // whatever you need

  def receive = initial(keys.map { k => (k -> None) })

}

(警告:未编译)