2016-07-28 14 views
2

I die folgende Iterator habe:Iterieren in Scala: Prüfen, vorherigen Werte

val it = Iterator(("a",5),("a",3),("a",2),("a",1),("b",8),("b",2),("b",1),("c",1)) 

Die inneren Werte sortiert werden zunächst durch das erste Element (String) und andererseits von der zweiten (Int). Wie kann ich die ersten 2 Werte von jedem Buchstaben erhalten? So sollte das Ergebnis in diesem Beispiel sein:

Iterator(("a",5),("a",3),("b",8),("b",2),("c",1)) 

Es kann mit groupBy erfolgen:

it.toList.groupBy(_._1).mapValues(_.take(2)).values.flatten.toIterator 

aber ich möchte eine Lösung finden, die durch jedes Element geht und überprüfen Sie die vorherigen ‚string‘ Element und wenn es die gleiche und die 'Anzahl' ist kleiner als 2 dann ist es yield dieser Wert.

bearbeiten:

Nach der Logik der @jwvh Antwort: Wie kann es die ersten N-Werte anstelle der ersten 2 nehmen verallgemeinert werden?

Antwort

2

Es wäre schön, wenn wir nicht müssen den gesamten Iterator auf einmal verbrauchen.

val repLimitedItr = LimitItr(itrOfTuples, numOfRepetitionsAllowed) 
+0

danke! Ich habe versucht, die Ergebnisse in einer 'while'-Schleife auszugeben:' while (lit.hasNext()) {yield.next()} 'aber es funktioniert nicht. Gibt es einen Weg, es zu tun? –

+0

oder wird diese 'für (elem <- lit) yield elem 'als eine gute Praxis angesehen? –

+0

Ich entschuldige mich für die Kommentare. wie könnte dies auf N erste Werte statt auf die ersten 2 verallgemeinert werden? –

3

könnten Sie verwenden einen fold Betrieb, aber es ist umständlicher als Ihre Lösung:

val result = it.foldLeft((Seq[(String, Int)](), "", 0)){ 
    case ((acc, prev, count), (l, n)) => 
    if (prev == l) { 
     if (count < 2) (acc :+ (l, n), prev, count + 1) 
     else (acc, prev, count + 1) 
    } 
    else (acc :+ (l, n), l, 1) 
} 

println(result._1) 
2

Eine andere Lösung foldLeft verwendet, könnte sein:

it.foldLeft (List[(String, Int)]()) { 
    case (acc, (k,v)) if acc.takeWhile(_._1==k).size<2 => (k,v)::acc 
    case (acc, _) => acc 
}.reverse 
+0

Kühler ein:

case class LimitItr[A,B](var itr: Iterator[(A,B)], reps:Int) extends Iterator[(A,B)] { private var memory: List[A] = List() def hasNext = itr.hasNext def next() = { val current = itr.next if (!memory.headOption.contains(current._1)) memory = List() memory = current._1 :: memory if (memory.length >= reps) { itr = itr.dropWhile(_._1 == memory.head) itr.hasNext // force the iterator forward } current } } 

Nutzungs AKTUALISIERT! Gibt es eine Möglichkeit, 'yield' in Ihrer Antwort zu verwenden, anstatt sie zu einem Endergebnis zu" speichern "? –

Verwandte Themen