2017-09-04 2 views
0

Ich versuche, einige Codes wie unten zu schreiben -Scala: Wie für das Verständnis von einem verschachtelten brechen

def kthSmallest(matrix: Array[Array[Int]], k: Int): Int = { 
    val pq = new PriorityQueue[Int]() //natural ordering 
    var count = 0 

    for (
    i <- matrix.indices; 
    j <- matrix(0).indices 
) yield { 
     pq += matrix(i)(j) 
     count += 1 
    } //This would yield Any! 

    pq.dequeue() //kth smallest. 

} 

Meine Frage ist, dass ich nur eine Schleife wollen, bis die Zeitzählung kleiner als k (etwas wie takeWhile (count! = k)), aber da ich auch Elemente in die Prioritätswarteschlange in der Ausbeute einfüge, wird dies im aktuellen Zustand nicht funktionieren.

Meine anderen Optionen sind, eine verschachtelte Schleife zu schreiben und zurückzukehren, sobald die Anzahl k erreicht. Ist es möglich mit Ertrag zu tun? Ich konnte es noch nicht idiomatisch finden. Alle Hinweise wären hilfreich.

+1

Sie zwingend notwendig und zweckmäßig sind mischen. Sie tun dies entweder voll funktionsfähig (Entfernen der Warteschlange) oder Sie tun es völlig imperativ (mit einer regulären for-Schleife, daher die Ausbeute zu entfernen) – Chobeat

+0

Die PriorityQueue ist eine Implementierung von scala.collection.mutable. Wie sonst zu einer veränderbaren Sammlung hinzufügen? – learningTheRopes

+0

@ Chobeat warum? Es ist perfekt machbar, Konzepte aus beiden Paradigmen zu mischen. – pedromss

Antwort

1

Es ist nicht idiomatisch für Scala, var s oder Break-Schleifen zu verwenden. Sie können für Rekursion, faule Bewertung oder Klebeband eine break gehen, auf etwas Leistung (wie return, es ist als Ausnahme implementiert, und wird nicht gut genug). Hier sind die Optionen unterteilt:

  1. Verwendung Rekursion - rekursive Algorithmen sind die analoge von Schleifen in funktionalen Sprachen

    def kthSmallest(matrix: Array[Array[Int]], k: Int): Int = { 
        val pq = new PriorityQueue[Int]() //natural ordering 
    
        @tailrec 
        def fillQueue(i: Int, j: Int, count: Int): Unit = 
        if (count >= k || i >= matrix.length)() 
        else { 
         pq += matrix(i)(j) 
         fillQueue(
         if (j >= matrix(i).length - 1) i + 1 else i, 
         if (j >= matrix(i).length - 1) 0 else j + 1, 
         count + 1) 
        } 
    
        fillQueue(0, 0, 0) 
    
        pq.dequeue() //kth smallest. 
    } 
    
  2. Verwenden Sie eine faule Struktur, wie chengpohi vorgeschlagen - dies nicht sehr klingen ähnlich wie eine reine Funktion. Ich würde vorschlagen, in diesem Fall eine Iterator anstelle einer Stream zu verwenden - da Iteratoren nicht die Schritte notieren, die sie durchlaufen haben (könnte Speicher für große Matrizen verschonen).

  3. Für bereit diejenigen verzweifelt break zu verwenden, unterstützt Scala es in einem aufsetzbaren Art und Weise (beachten Sie die Leistung Vorbehalt oben erwähnt):

    import scala.util.control.Breaks 
    
    breakable { 
        // loop code 
        break 
    } 
    
+0

Danke! Das hilft. Ich hatte das Gefühl "recurse stattdessen!" wäre die Antwort :) – learningTheRopes

+0

dieser Algorithmus ist falsch, in mehr als einer Hinsicht. – Dima

1

Es gibt einen Weg mit der Streamfaul Bewertung, dies zu tun. Da for yield-flatMap gleich ist, können Sie for yield-flatMap mit Stream konvertieren:

matrix.indices.toStream.flatMap(i => { 
    matrix(0).indices.toStream.map(j => { 
    pq += matrix(i)(j) 
    count += 1 
    }) 
}).takeWhile(_ => count <= k) 

Verwenden toStream die Sammlung zu Stream, konvertieren und da Stream ist lazy evaluation, so können wir takeWhile zu verwenden Prädikat count, um die weniger Schleifen ohne init andere zu beenden.

+0

Ich glaube nicht, dass es ein 'Stream' ist, der dir etwas kauft.Nach all dem sitzt die Matrix schon im Gedächtnis. Konvertieren es in eine Reihe von verschachtelten 'Streams' zuerst ändert sich nicht das – badcook

+0

'Stream' ist faul oder? Die Zählung ist auch faul zu berechnen. – chengpohi

+0

Ach, macht nichts, ich habe zu schnell gelesen und ich habe mich geirrt; Ich sehe was du hier machst. In diesem Fall stimme ich @Sergey zu. Die Tatsache, dass jedes Element des Streams für seine Nebenwirkungen bewertet und sofort weggeworfen wird, ohne jemals seine Elemente zu inspizieren, fühlt sich nicht idiomatisch an. – badcook

Verwandte Themen