0

Im trying to add items to a ListBuffer (or any other structure ?) basically i'm trying to create a list of PostMD objects by using this method.

def getData(url: String, userID: String): ListBuffer[PostMD] = {
  val chunk: JsValue = BusinessLogic.Methods.getJsonValue(url)
  val postMd: List[PostMD] = for {
    x <- (chunk \ "data").as[List[JsValue]]
  } yield x.as[PostMD]

  val filtered: ListBuffer[PostMD] = 
    postMd.filter(_.fromID == userID).to[ListBuffer])

  if ((chunk \ "paging" \ "next").toString() != null) 
    getData(chunk.\("paging").\("next").toString(), userID)

  return filtered
}

Obviously im doing something wrong... what will be the best way to add item to a list inside a recursive method ?

thanks

miki

Martin Ring
  • 5,404
  • 24
  • 47
MIkCode
  • 2,655
  • 5
  • 28
  • 46
  • You mean something like `return filtered :: getData(chunk.\("paging").\("next").toString(), userID)`? Option B is to add a list parameter and simply add them to it and return nothing. – rlegendi Oct 15 '14 at 12:19

2 Answers2

1

You are making a recursive call, but you are ignoring its result. (In fact, any time you have an if without an else the expression inside the if is evaluated for side effects only).

assuming what you want is the results of the recursive call appended to your filtered ListBuffer, then perhaps change your expression to:

if ((chunk \ "paging" \ "next").toString() != null) 
  filtered ++ getData(chunk.\("paging").\("next").toString(), userID)
else filtered

And get rid of the return statement. (return statements should really be avoided, they should be never needed).

Note that this is not tail-recursive, and it will blow the stack if the discriminator you are passing to the if is true too man times before it is false. In order to make this tail-recursive, you might make the recursive bit an inner function which passes the list buffer you are appending to as a parameter to the recursive function.

stew
  • 11,276
  • 36
  • 49
  • This both blows the stack and creates a new ListBuffer every iteration, and does O(n*m) work (where m is the number of iterations) just moving contents from one collection to another. – Rex Kerr Oct 15 '14 at 15:28
  • i couldn't find or implement a tail recursion example for a Listbuffer. can you please give me example thanks miki – MIkCode Oct 15 '14 at 17:39
1

It's often easiest to create an inner helper method to do recursion with a mutable collection. Like so:

def getData(url: String, userID: String): ListBuffer[PostMD] = {
  val filtered = ListBuffer.empty[PostMD]
  def inner(url: String) {
     val chunk = ...
     val postMD = ...
     filtered ++= postMD.filter(_.fromID == userID)
     val next = (chunk \ "paging" \ "next").toString
     if (next != null) inner(next)
  }
  inner(url)
  filtered
}
Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • Because you are creating "val filtered" outside of the recursion this method is "Stack" safe ?? – MIkCode Oct 15 '14 at 17:41
  • I think it should be filtered ++= postMD.filter(_.fromID == userID) Because postMD.filte return a list of PostMD Objects – MIkCode Oct 15 '14 at 18:08
  • @MlkCode - Yes, it should; I didn't compile it (fixed now). It's stack-safe because it's tail-recursive. You can also pass the ListBuffer forward in each recursion to make it tail-recursive. You can check with `@annotation.tailrec` (but the annotation only tells you when it's not, it doesn't change whether or not it actually is tail-recursive). – Rex Kerr Oct 15 '14 at 19:31