Scala 在我的算法中替换命令优先队列

Scala 在我的算法中替换命令优先队列,scala,priority-queue,sortedset,declarative-programming,Scala,Priority Queue,Sortedset,Declarative Programming,我目前有一个方法,它使用scala.collection.mutable.PriorityQueue按特定顺序组合元素。例如,代码看起来有点像这样: def process[A : Ordering](as: Set[A], f: (A, A) => A): A = { val queue = new scala.collection.mutable.PriorityQueue[A]() ++ as while (queue.size > 1) { val a

我目前有一个方法,它使用scala.collection.mutable.PriorityQueue按特定顺序组合元素。例如,代码看起来有点像这样:

 def process[A : Ordering](as: Set[A], f: (A, A) => A): A = {
   val queue = new scala.collection.mutable.PriorityQueue[A]() ++ as
   while (queue.size > 1) {
     val a1 = queue.dequeue
     val a2 = queue.dequeue
     queue.enqueue(f(a1, a2))
   }
   queue.dequeue
 }

代码按编写的方式工作,但必须非常必要。我曾想过使用SortedSet而不是PriorityQueue,但我的尝试使这个过程看起来更加混乱。做我想做的事情,有什么更具声明性、更简洁的方法吗?

如果f不生成集合中已经存在的元素,您确实可以使用
SortedSet
。(如果有,您需要一个不可变优先级队列。)实现这一点的声明性方法是:

def process[A:Ordering](s:SortedSet[A], f:(A,A)=>A):A = {
  if (s.size == 1) s.head else {
    val fst::snd::Nil = s.take(2).toList
    val newSet = s - fst - snd + f(fst, snd)
    process(newSet, f)
  }
}

试图改进@Kim Stebel的答案,但我认为命令式变体更为清晰

def process[A:Ordering](s: Set[A], f: (A, A) => A): A = {
  val ord = implicitly[Ordering[A]]
  @tailrec
  def loop(lst: List[A]): A = lst match {
    case result :: Nil => result
    case fst :: snd :: rest =>
      val insert = f(fst, snd)
      val (more, less) = rest.span(ord.gt(_, insert))
      loop(more ::: insert :: less)    
  }
  loop(s.toList.sorted(ord.reverse))
}

下面是一个使用
分类数据集
的解决方案:

def process[A : Ordering](as: Set[A], f: (A, A) => A): A = {
    Stream.iterate(SortedSet.empty ++ as)(  ss => 
        ss.drop(2) + f(ss.head, ss.tail.head))
    .takeWhile(_.size > 1).last.head
}

我不得不说OP的命令式版本更清晰。这将是有用的,如果有一个多项目出列功能…我清理了一点,看不出什么是更清楚的OP的版本了。这只是你习惯了什么的问题。我不认为这只是你习惯了什么。这是s-fst-snd+。。。等等,不使用出列意味着你要做两次事情——一次是访问两个最上面的元素,然后将它们传递给f。一次构造队列的剩余部分,不使用它们。“出列”可以很好地捕获这两种情况。使用提取器返回前两个和队列的其余部分可能会有所帮助?这可能是一个不同的问题,但在这种情况下,是否有理由选择Stream.iterate而不是Iterator.iterate?@Garrett一点也没有——事实上,恰恰相反。但是,
迭代器
是不起作用的,如果要用函数替换“命令式”代码。。。