Home > Software engineering >  Flatmap merging an internal iterator
Flatmap merging an internal iterator

Time:02-10

I'm trying to convert an Iterator[String] to Iterator[CustomClass], where CustomClass is self-explanatory and doesn't need to have much detail here.

The workflow is:

Iterator[String] -> Iterator[Array[Byte]] -> Iterator[CustomClass]

What I have so far:

def extractAsCustomClass(strings: Iterator[String]): Iterator[CustomClass] = {
  val byteArrayIt = strings.flatMap(toByteArrayIterator)
  val customClassIt = byteArrayIt.flatMap(toCustomClassIterator)
  customClassIt
}

private def toByteArrayIterator(data: String): Iterator[Array[Byte]] = { // converts to byte array }
private def toCustomClassIterator(blob: Array[Byte]): Iterator[CustomClass] = { // converts to custom class }

With this, my end result is an Iterator[CustomClass] that contains one element where all the input byte arrays were combined into one byte array. So if I call extractAsCustomClass with a String iterator that has two elements, the end result would be Iterator[CustomClass] which only has one, combined element.

Using the example above of an input String iterator with two elements, I instead want an Iterator[CustomClass] that contains two CustomClass elements, where each String has gone from

String -> Array[Byte] -> CustomClass

I've tried playing around with map and flatMap but it either creates iterators of iterators or a combined element.

CodePudding user response:

You've got yourself a little bit tangled up; it's way easier than you think it is! :-)

Remember that for some container type C holding items of type A (i.e. C[A]) if you want to get a C[B] (i.e. a container holding items of type B) then just supply the way to get from A to B as the argument to map. You don't need to worry about the outer container type C at all.

So in your case, the functions you need to supply would just be:

private def toByteArray(data: String): Array[Byte]

private def toCustomClass(blob: Array[Byte]): CustomClass

Notice how they don't mention Iterator anywhere. A great benefit - they're much more useful and re-usable as a result.

So for a complete worked (and working!) example:

case class CustomClass(foo: String)

private def toByteArray(data: String): Array[Byte] = {
  // converts to byte array
  data.getBytes
}

private def toCustomClass(blob: Array[Byte]): CustomClass = {
   // converts to custom class
   val s = new String(blob)
   CustomClass(s)
}

Now your extract function is just:

def extractAsCustomClass(strings: Iterator[String]): Iterator[CustomClass] = {
  val byteArrayIt = strings.map(toByteArray)
  val customClassIt = byteArrayIt.map(toCustomClass)
  customClassIt
}
  • Related