Reputation: 318
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
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
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