Based on the description of the question, and subsequent comments, I am assuming there exists multiple Iterator[Char]
sources:
val allSources : Iterable[Iterator[Char]] = ???
And the question is: how to concurrently collect String
values from these Iterators to form a mapping of String to count.
Stream Based Solution
First we need to convert each of the Iterators to an Iterator of String values based on a separator:
trait Word {
val data : String
}
object EmptyWord extends Word {
override val data = ""
}
case class PartialWord(val data : String) extends Word
case class WholeWord(val data : String) extends Word
val appendToWord : Char => (Word, Char) => Word =
(separator) => (originalWord, appendChar) => originalWord match {
case PartialWord(d) =>
if(appendChar == separator)
WholeWord(d)
else
PartialWord(d + appendChar)
case _ => PartialWord(appendChar.toString)
}
val isWholeWord : Word => Boolean = (_ : Word) match {
case _ : WholeWord => true
case _ => false
}
//using space as separator
val convertCharIterator : Iterator[Char] => Iterator[String] =
(_ : Iterator[Char])
.scanLeft(EmptyWord)(appendToWord(' '))
.filter(isWholeWord)
.map(_.data)
We can now convert all of the Iterators to generate Strings and we can combine all of the Iterators into a single Iterator:
val allWordSource : Iterator[String] =
allSources.map(convertCharIterator)
.reduceOption( _ ++ _)
.getOrElse(Iterator.empty[String])
This Iterator can now be the source of an akka stream which will calculate your count:
val addToCounter : (Map[String, Int], String) => Map[String, Int] =
(counter, word) =>
counter.updated(word, counter.getOrElse(word, 0) + 1)
val counter : Future[Map[String, Int]] =
Source
.fromIterator( () => allWordSource)
.runFold(Map.empty[String, Int])(addToCounter)