我在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
数据是多余的,因此我会在值列表完成后将它们丢弃。
告诉我你有什么!
答案 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) })
}
(警告:未编译)