Tilney
Tilney

Reputation: 318

How can I implement partial reduce in scala?

Here is the scene: only reduce elements under some specified circumstances.

Eg. val sen = List("Jone", "had", "a", "great", "time", "."), if element ends up with "e", so concatenate it with the next element. For sen, the result could be ("Jone had", "a", "great", "time .").

Is there any elegant way to achieve these rather than a loop?

Upvotes: 0

Views: 186

Answers (2)

Justin Pihony
Justin Pihony

Reputation: 67135

A foldLeft as @kaktusito posted is the best way. Below is the internals of how it works....for the most part.

def partialReduce(list : List[String]): List[String] = {
  @scala.annotation.tailrec
  def internalRecurse(previousWord: String)(reducedList: List[String], finalList: List[String]): List[String] = 
    reducedList match {
      case Nil => finalList :+ previousWord //No more words, just add the previous to the list and return
      case head :: rest => {
        //if ends with e, run through the rest with the new word being the old + the head
        if(previousWord endsWith "e") internalRecurse(previousWord + " " + head)(rest, finalList)
        //if doesn't end with e, append the previous word to the final list 
        //and run the rest with the head as the next to check
        else internalRecurse(head)(rest, finalList :+ previousWord)
      }
    }

  //Call the internal method only if there is at least one item in the list
  list match {
    case Nil => Nil
    case head :: rest => internalRecurse(head)(rest, List())
  }
}

Also, I am going to post my pattern matching version as I like the look better:

val result = sen.foldLeft(List[String]()) {
    (curList, s) => {
       curList match {
         case Nil => List(s)
         case head :: rest => {
           if(head endsWith "e") head + " " + s :: rest
           else s :: curList
         }
       }
    }   
  }.reverse

Upvotes: 2

ale64bit
ale64bit

Reputation: 6242

You can simply use foldLeft as in:

val result = sen.foldLeft(List[String]()) {
    (rs, s) => 
      if (rs.nonEmpty && rs.head.endsWith("e")) 
        (rs.head + " " + s) :: rs.tail 
      else 
        s :: rs
  }.reverse

Just replace rs.head.endsWith("e") with your own function.

Upvotes: 4

Related Questions