kotlincollectionswindowed

why is the result of "windowed" different?


Code with List:

println(listOf(1, 2, 3).windowed(1))
println(listOf(1, 2, 3).windowed(1) { it })
println(listOf(1, 2, 3).windowed(1) { it.toList() })

Result:

[[1], [2], [3]]
[[3], [3], [3]]  //why is there 3 everywhere?
[[1], [2], [3]]

Code with Sequence:

println(sequenceOf(1, 2, 3).windowed(1).toList())
println(sequenceOf(1, 2, 3).windowed(1) { it }.toList())
println(sequenceOf(1, 2, 3).windowed(1) { it.toList() }.toList())

Result:

[[1], [2], [3]]
[[], [], []]     //why?!
[[1], [2], [3]]

Please explain


Solution

  • It is in the documentation for the function:

    Note that the list passed to the transform function is ephemeral and is valid only inside that function. You should not store it or allow it to escape in some way, unless you made a snapshot of it.

    As an implementation detail, this higher order function is reusing the same list instance for each element of the window and clearing/refilling it in between. This avoids having to allocate many lists.

    By passing it as the return value of the transform function, you are allowing the list instance to escape, as they warn you not to do.

    In your third example, you are returning a copy of the list using toList(), so it works correctly.

    When you do this with sequences, the results are different because the function internally handles lists and other iterable types differently. Perhaps the algorithm empties the reused list at the end.