How can nested lists be declared in Kotlin? I'm looking for something in the form of:
var nestedList:List = [1,[2,[3,null,4]],[null],5]
so that I can flatten it later on (result should be nestedList = [1, 2, 3, 4, 5]).
If you have nested arrays structure (for instance, val array: Array<Array<out Int?>> = arrayOf(arrayOf(1), arrayOf(2), arrayOf(3, null, 4))
), you can just use flatten
extension method:
println(array.flatten().filterNotNull())
All common collections can't maintain variable layers count, so with them you can make only something like Andrey Ilyunin wrote - val array: Array<Array<out Int?>>
.
But I wrote class structure to help you with your goal. It is no another collection and you can't work with it like it is, but it can make any layers amount you want. It is totally generic, so you can put there not only Int
.
First of all, we start with NestedArrayItem
class, which represents single item or one more nested array:
class NestedArrayItem<T> {
private val array: ArrayList<NestedArrayItem<T>>?
private val singleItem: T?
constructor(array: ArrayList<NestedArrayItem<T>>) {
this.array = array
singleItem = null
}
constructor(singleItem: T?) {
this.singleItem = singleItem
array = null
}
fun asSequence(): Sequence<T?> =
array?.asSequence()?.flatMap { it.asSequence() } ?:
sequenceOf(singleItem)
override fun toString() =
array?.joinToString(prefix = "[", postfix = "]") ?:
singleItem?.toString() ?: "null"
}
Then class NestedArray
that is just like top level container for all the layers:
class NestedArray<T> {
private val array: ArrayList<NestedArrayItem<T>> = arrayListOf()
fun add(value: T?) {
array.add(NestedArrayItem(value))
}
fun addNested(nestedArray: NestedArray<T>) {
array.add(NestedArrayItem(nestedArray.array))
}
fun flatten(): ArrayList<T?> = array.asSequence()
.flatMap { it.asSequence() }
.toCollection(arrayListOf())
override fun toString() = array.joinToString(prefix = "[", postfix = "]")
}
And to make it easier to write values I additionally wrote builder class for that:
class NestedArrayBuilder<T> private constructor(private val result: NestedArray<T>){
constructor(fillNestedBuilder: NestedArrayBuilder<T>.() -> Unit) : this(NestedArray()) {
NestedArrayBuilder(result).apply(fillNestedBuilder)
}
fun add(value: T?): NestedArrayBuilder<T> {
result.add(value)
return this
}
fun addArray(fillNestedBuilder: NestedArrayBuilder<T>.() -> Unit): NestedArrayBuilder<T> {
val nestedResult = NestedArray<T>()
val nestedArray = NestedArrayBuilder(nestedResult).apply(fillNestedBuilder)
.build()
result.addNested(nestedArray)
return this
}
fun build() = result
}
That's it! You can use it. I put here example how to use it:
val array = NestedArrayBuilder<Int> {
add(1)
addArray {
add(2)
addArray {
add(3)
add(null)
add(4)
}
}
addArray {
add(null)
}
add(5)
}.build()
assertEquals("[1, [2, [3, null, 4]], [null], 5]", array.toString())
assertEquals(arrayListOf(1, 2, 3, null, 4, null, 5), array.flatten())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With