Simplest way to get the top n elements of a Scala Iterable

前端 未结 9 650
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-29 02:48

Is there a simple and efficient solution to determine the top n elements of a Scala Iterable? I mean something like

iter.toList.sortBy(_.myAttr).take(2)
         


        
9条回答
  •  独厮守ぢ
    2020-11-29 03:19

    An optimised solution using PriorityQueue with Time Complexity of O(nlogk). In the approach given in the update, you are sorting the sofar list every time which is not needed and below it is optimised by using PriorityQueue.

    import scala.language.implicitConversions
    import scala.language.reflectiveCalls
    import collection.mutable.PriorityQueue
    implicit def iterExt[A](iter: Iterable[A]) = new {
        def top[B](n: Int, f: A => B)(implicit ord: Ordering[B]) : List[A] = {
            def updateSofar (sofar: PriorityQueue[A], el: A): PriorityQueue[A] = {
                if (ord.compare(f(el), f(sofar.head)) < 0){
                    sofar.dequeue
                    sofar.enqueue(el)
                }
                sofar
            }
    
            val (sofar, rest) = iter.splitAt(n)
            (PriorityQueue(sofar.toSeq:_*)( Ordering.by( (x :A) => f(x) ) ) /: rest) (updateSofar (_, _)).dequeueAll.toList.reverse
        }
    }
    
    case class A(s: String, i: Int)
    val li = List (4, 3, 6, 7, 1, 2, 9, 5).map(i => A(i.toString(), i))
    println(li.top(3, -_.i))
    

提交回复
热议问题