1

Newbie question. I am looping through a list and need keep state in between the items. For instance

 val l = List("a", "1", "2", "3", "b", "4") var state: String = "" l.foreach(o => { if (toInt(o).isEmpty) state = o else println(state + o.toString) }) 

what's the alternative for the usage of var here?

3
  • Can you give us an example of code that didn't work? I think I know what you're asking but I'm unclear. Commented Sep 8, 2016 at 19:36
  • 4
    foldLeft is what is used in FP to keep state Commented Sep 8, 2016 at 19:39
  • @wheaties - I have changed the question to include a code sample, I believe it is clear now. Thanks! Commented Sep 8, 2016 at 20:12

5 Answers 5

2

You should keep in mind that it's sometimes (read: when it makes the code more readable and maintainable by others) okay to use mutability when performing some operation that's easily expressed with mutable state as long as that mutable state is confined to as little of your program as possible. Using (e.g.) foldLeft to maintain an accumulator here without using a var doesn't gain you much.

That said, here's one way to go about doing this:

val listOfThings: Seq[Either[Char, Int]] = Seq(Left('a'), Right(11), Right(212), Left('b'), Right(89)) val result = listOfThings.foldLeft(Seq[(Char, Seq[Int])]()) { case (accumulator, Left(nextChar)) => accumulator :+ (nextChar, Seq.empty) case (accumulator, Right(nextInt)) => val (currentChar, currentSequence) = accumulator.last accumulator.dropRight(1) :+ (currentChar, currentSequence :+ nextInt) } result foreach { case (char, numbers) => println(numbers.map(num => s"$char-$num").mkString(" ")) } 
Sign up to request clarification or add additional context in comments.

2 Comments

It's a bad idea to take last or append to List, much better to reverse it or use ListBuffer
Also I would argue that imperative solution will not be much more readable than yours (provided that you want to keep result as a variable).
2

Use foldLeft:

l.foldLeft(""){ (state, o) => if(toInt(o).isEmpty) o else { println(state + o.toString) state } } 

Comments

0

Pass an arg:

scala> def collapse(header: String, vs: List[String]): Unit = vs match { | case Nil => | case h :: t if h.forall(Character.isDigit) => println(s"$header$h") ; collapse(header, t) | case h :: t => collapse(h, t) | } collapse: (header: String, vs: List[String])Unit scala> collapse("", vs) a1 a2 a3 b4 

Comments

0

As simple as:

val list: List[Int] = List.range(1, 10) // Create list def updateState(i : Int) : Int = i + 1 // Generate new state, just add one to each position. That will be the state list.foldRight[List[(Int,Int)]](List())((a, b) => (a, updateState(a)) :: b) 

Note that the result is a list of Tuple2: (Element, State), and each state depends on the element of the list.

Hope this helps

Comments

0

There are two major options to pass a state in functional programming when processing collections (I assume you want to get your result as a variable):

Recursion (classic)

val xs = List("a", "11", "212", "b", "89") @annotation.tailrec def fold(seq: ListBuffer[(String, ListBuffer[String])], xs: Seq[String]): ListBuffer[(String, ListBuffer[String])] = { (seq, xs) match { case (_, Nil) => seq case (_, c :: tail) if toInt(c).isEmpty => fold(seq :+ ((c, ListBuffer[String]())), tail) case (init :+ ((c, seq)), i :: tail) => fold(init :+ ((c, seq :+ i)), tail) } } val result = fold(ListBuffer[(String, ListBuffer[String])](), xs) // Get rid of mutable ListBuffer .toSeq .map { case (c, seq) => (c, seq.toSeq) } //> List((a,List(11, 212)), (b,List(89))) 

foldLeft et al.

val xs = List("a", "11", "212", "b", "89") val result = xs.foldLeft( ListBuffer[(String, ListBuffer[String])]() ) { case (seq, c) if toInt(c).isEmpty => seq :+ ((c, ListBuffer[String]())) case (init :+ ((c, seq)), i) => init :+ ((c, seq :+ i)) } // Get rid of mutable ListBuffer .toSeq .map { case (c, seq) => (c, seq.toSeq) } //> List((a,List(11, 212)), (b,List(89))) 

Which one is better? Unless you want to abort your processing in the middle of your collection (like e.g. in find) foldLeft is considered a better way and it has slightly less boilerplate, but otherwise they are very similar.

I'm using ListBuffer here to avoid reversing lists.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.