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)