Consider adding to stdlib. For when you want to split a list into two, at a given index: gist. Iterates once over the list.
val list = (0 until 10).toList()
list.splitAt(3).let { (left, right) ->
println(left) //=> [0, 1, 2]
println(right) //=> [3, 4, 5, 6, 7, 8, 9]
}
1 Like
First I guess you meant to split at index 4 and not 50. Otherwise your example makes no sense.
My problem with this method is, that it copies the entire list which can be very expensive depending on the size of the list. I am not sure if this is intentionally as I am not sure where exactly I would use this method. Can you give an example of where this might improve the code quality? Most examples I can think of would just use one of the 2 results in which case a function like subList
might be more suitable (even though subList does not create a copy, which IMO is good).
True, although it copies references (based on List.take()
). If partition()
had a partitionWithIndex
version, that would work (withIndex().partition()
returns IndexedValues
which requires unwrapping).
Use case: batching incoming list of items (requires tracking remainders):
remainder = (remainder + someList)
.splitAt(whereToSplit())
.let { (items, remainder) ->
doSomethingWith(items)
remainder
}
This is exactly the kind of example where copying all the references could cost a lot of speed and the usage of subList
would be beneficiary as you do not modify the lists. Therefore the 2 split parts can be implemented as a “container” pointing to a region of the original list, which makes splitting much faster because you do not need to copy any elements. If you want to modify the 2 split parts you could still create a new list copying the elements eg. by using ArrayList(original)
.
That’s true for List<T>
I am not really sure what you mean by that. What exactly is true for List<T>
?
Sorry, I meant that a specialization for List
can definitely use subList
. The current receiver is Iterable