替换我的算法中的命令式 PriorityQueue

发布于 2024-11-25 01:26:25 字数 488 浏览 2 评论 0原文

我目前有一个方法,使用 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,但我的尝试使该过程看起来更加混乱。什么是更明确、更简洁的方式来做我想做的事情?

I currently have a method that uses a scala.collection.mutable.PriorityQueue to combine elements in a certain order. For instance the code looks a bit like this:

 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
 }

The code works as written, but is necessarily pretty imperative. I thought of using a SortedSet instead of the PriorityQueue, but my attempts make the process look a lot messier. What is a more declarative, succinct way of doing what I want to do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

飞烟轻若梦 2024-12-02 01:26:25

如果 f 不产生 Set 中已有的元素,那么您确实可以使用 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)
  }
}

If f doesn't produce elements that are already in the Set, you can indeed use a SortedSet. (If it does, you need an immutable priority queue.) A declarative wayto do this would be:

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)
  }
}
勿忘初心 2024-12-02 01:26:25

试图改进@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))
}

Tried to improve @Kim Stebel's answer, but I think imperative variant is still more clear.

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))
}
归途 2024-12-02 01:26:25

这是使用 SortedSetStream 的解决方案:

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
}

Here's a solution with SortedSet and Stream:

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文