You code snippet does not work very well, I had to tweak it a bit to make it output the result you want:
var log = 0 var idx = 0 val resultList: mutable.ListBuffer[Int] = mutable.ListBuffer() // Fill the result until the middle, increasing the jump size while (idx < list.size / 2) { resultList += list(idx) idx += math.pow(2, log).toInt log += 1 } // Fill the result from the middle until the end, decreasing the jump size again while (idx < list.size && log >= 0) { resultList += list(idx) log -= 1 idx += math.pow(2, log).toInt }
With your example it works:
val list = (0 to 13).toList -> ListBuffer(0, 1, 3, 7, 11, 13)
However with another example I got that:
val list = (0 to 22).toList -> ListBuffer(0, 1, 3, 7, 15)
I don't think this is really what you want, do you?
Anyway here is a more functionnal version of it:
def filter(list: List[Int]) = { // recursive function to traverse the list def recursive(l: List[Int], log: Int, idx: Int, size: Int, halfSize: Int): List[Int] = { if (idx >= l.size || log < 0) // terminal case: end of the list Nil else if (idx < l.size / 2) // first half of the list: increase the jump size l(idx) :: recursive(l, log + 1, idx + math.pow(2, log).toInt, size, halfSize) else // second half of the list: decrease the jump size l(idx) :: recursive(l, log - 1, idx + math.pow(2, log-1).toInt, size, halfSize) } // call the recursive function with initial parameters recursive(list, 0, 0, list.size, list.size / 2) }
However, jumping by powers if 2 is too aggressive. If you are near the middle of the list, the next jump will ends at the very end, and you will not be able to get a progressive jump decay.
Another solution could be to increase the jump size by one each time instead of working with powers of 2. You can also keep a constant jump size when you are near the middle of the list to avoid skipping too much values in the second half before starting to reduce the jump size:
def filter2(list: List[Int]) = { def recursive(l: List[Int], jumpsize: Int, idx: Int, size: Int, halfSize: Int): List[Int] = { if (idx >= l.size) // terminal case: end of the list Nil else if (idx + jumpsize < l.size/2) // first half of the list: increase the jump size l(idx) :: recursive(l, jumpsize+1, idx + jumpsize, size, halfSize) else if (idx < l.size/2) // around the middle of the list: keep the jump size l(idx) :: recursive(l, jumpsize, idx + jumpsize, size, halfSize) else { // second half of the list: decrease the jump size val nextJumpSize = jumpsize - 1 l(idx) :: recursive(l, nextJumpSize, idx + nextJumpSize, size, halfSize) } } // call the recursive function with initial parameters recursive(list, 1, 0, list.size, list.size / 2) }
In my opinion, the results with this version are a bit better:
val list = (0 to 22).toList -> List(0, 1, 3, 6, 10, 15, 19, 22)