8

In Java or Kotlin, how can I create as much of a sublist as possible? If the range is greater than the size of the list, it should just ignore parts of the range that are out of bounds.

I currently have (Kotlin):

val list: List = arrayListOf(1, 2, 3, 4)
list.subList(0, 3) // -> [1, 2, 3]
list.subList(0, 5) // -> IndexOutOfBoundsException
list.subList(0, 200) // -> IndexOutOfBoundsException
list.clear()
list.subList(0, 3) // -> IndexOutOfBoundsException

I would like (Kotlin):

val list: List = arrayListOf(1, 2, 3, 4)
list.subList(0, 3) // -> [1, 2, 3]
list.subList(0, 5) // -> [1, 2, 3, 4]
list.subList(0, 200) // -> [1, 2, 3, 4]
list.clear()
list.subList(0, 3) // -> []
David Callanan
  • 5,601
  • 7
  • 63
  • 105

4 Answers4

13

You could write an extension on List<T> to do this logic for you:

fun <T> List<T>.safeSubList(fromIndex: Int, toIndex: Int): List<T> =
    this.subList(fromIndex, toIndex.coerceAtMost(this.size))

This uses coerceAtMost to limit the highest value.

And to call it:

val list = arrayListOf(1, 2, 3, 4)
println(list.safeSubList(0, 200)) // -> [1, 2, 3, 4]

Or as @gidds suggests, we could make this even safer:

fun <T> List<T>.safeSubList(fromIndex: Int, toIndex: Int): List<T> = 
    this.subList(fromIndex.coerceAtLeast(0), toIndex.coerceAtMost(this.size))

This version guards against specifying numbers out of range on both ends. If you pass in numbers such that from > to, it will throw an IllegalArgumentException from subList.

Todd
  • 30,472
  • 11
  • 81
  • 89
  • 2
    That would be my approach, too.  You could make it even safer by limiting the fromValue, too; and by restricting them to be >= 0 as well as <= `size`; and possibly by ensuring `fromIndex` <= `toIndex` as well.  (Though arguably that might be _too_ safe…) – gidds Jan 01 '20 at 14:07
11

In Kotlin you can do

val list = mutableListOf(1, 2, 3, 4)
list.take(3) // -> [1, 2, 3]
list.take(5) // -> [1, 2, 3, 4]
list.take(200) // -> [1, 2, 3, 4]
list.clear()
list.take(3) // -> []

You can check the implementation of take if you'd like.

Felipe Conde
  • 2,024
  • 23
  • 26
2

Arraylist is implemented over array. so you can not be able to get sublist than the real amount.

arrayListOf(1, 2, 3, 4)

it means, You can only get the range between 0 - 4


You can try this to avoid IndexOutOfBoundsException

int maxRange = yourGivenMaxRange;

    if(maxRange > list.size()){
        maxRange = list.size();
    }

list.subList(0, maxRange) // -> [1, 2, 3]
list.subList(0, maxRange) // -> [1, 2, 3, 4]
list.subList(0, maxRange) // -> [1, 2, 3, 4]
list.clear()
list.subList(0, maxRange) // -> []
majurageerthan
  • 2,169
  • 3
  • 17
  • 30
1

It would be work.

import kotlin.math.max
import kotlin.math.min

fun <T> List<T>.safeSubList(fromIndex: Int, toIndex: Int): List<T> {
    if (fromIndex > toIndex) return emptyList()
    return subList(max(min(fromIndex.coerceAtLeast(0), size), 0), max(min(toIndex.coerceAtMost(size), size), 0))
}

example)

val a = (1..10).toList()
println(a.safeSubList(9, 10))
println(a.safeSubList(-1, -2))
println(a.safeSubList(1, 0))
println(a.safeSubList(-9, 4))
println(a.safeSubList(4, 5))
println(a.safeSubList(9, 15))

result)

[10]
[]
[]
[1, 2, 3, 4]
[5]
[10]