I fear I've missed something "standard" but I did try, honest!
I have been trying to understand how to implement efficient, tail-recursive, operations on linked lists. (I'm writing in Scala, but I doubt that's actually relevant).
Note: I am investigating this from a algorithms theory perspective, I'm not interested in "use the prebuilt library, it's already worked this out" :)
So, if I perform a trivial filter implementation to act on a list:
def filter[T](l: List[T])(f: T => Boolean): List[T] = l match {
case h :: t => if (f(h)) h :: filter(t)(f) else filter(t)(f)
case _ => List()
}
this isn't tail recursive, but it's tolerably efficient (in so far as it only prepends new items onto the result list it constructs)
However, the simple tail-recursive variant I came up with:
def filter[T](l: List[T])(f: T => Boolean): List[T] = {
@tailrec
def filterAcc[T](l: List[T], f: T => Boolean, acc: List[T]): List[T] = l match {
case List() => acc
case h :: t => if (f(h)) filterAcc(t, f, h :: acc) else filterAcc(t, f, acc)
}
filterAcc(l, f, List())
}
reverses the order of the items. (Which is not a surprise, of course!)
I could fix the order, of course, by appending the filtered item to the accumulator, but that would make this an O(n^2) implementation I believe (as each append would force building an entirely new list which is an O(n) operation on a Scala immutable list, times n repetitions for the n elements in the list)
I could also fix this by calling reverse on the generated list. I appreciate that this would be a single O(n) operation, and so the overall time complexity is still O(n), but it seems ugly.
So, my question is simply this; is there a solution that is tail-recursive, and accumulates in the correct order from the outset, that's O(n) and likely involves less work than the "catch it backwards and reverse it" option? Did I miss something (which is normal for me, I fear :( )
QueueorVectoras they offer (mostly) constant-time append.