Reputation: 60081
I have a below code which works.
class ListManipulate(val list: List<Char>, val blockCount: Int) {
val result: MutableList<List<Char>> = mutableListOf()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result.add(constructSequence(sequence))
return
}
for (i in start .. list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> {
var result = emptyList<Char>()
for (i in sequence) {
result += list[i]
}
return result
}
}
However, when I change the result
from MutableList to normal List, i.e.
var result: List<List<Char>> = emptyList()
// ...
result += constructSequence(sequence)
I got this error Type mismatch. Require: List<List<Char>>; Found: List<Any>
The full code as below
class ListManipulate(val list: List<Char>, val blockCount: Int) {
var result: List<List<Char>> = emptyList()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result += constructSequence(sequence)
return
}
for (i in start .. list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> {
var result = emptyList<Char>()
for (i in sequence) {
result += list[i]
}
return result
}
}
Why result + constructSequence(sequence)
would result in List<Any>
instead of List<List<Char>>
?
Is there a way I could still use the normal List> and not the mutable list?
Upvotes: 1
Views: 112
Reputation: 6793
The problem is that +=
is overloaded. If it sees an Iterable
, Array
or Sequence
it behaves differently. You have to explicitly use plusElement()
to achieve the behaviour you intend.
Consider the following code.:
class ListManipulate(val list: List<Char>, val blockCount: Int) {
var result: List<List<Char>> = emptyList()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result = result.plusElement(constructSequence(sequence))
return
}
for (i in start..list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> =
List(sequence.size, { i -> list[sequence[i]] })
}
PS: I also took the liberty to update your constructSequence()
to something more concise.
Btw: +=
uses addAll
internally.
/** * Returns a list containing all elements of the original collection and then all elements of the given [elements] collection. */ public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> { if (elements is Collection) { val result = ArrayList<T>(this.size + elements.size) result.addAll(this) result.addAll(elements) return result } else { val result = ArrayList<T>(this) result.addAll(elements) return result } }
Side note: you can also do:
result.toMutableList().add(constructSequence(sequence))
It is fine to return a MutableList
, the only difference really is that the List
interface doesnt have the manipulation methods. Internally both are represented by an ArrayList
@SinceKotlin("1.1") @kotlin.internal.InlineOnly public inline fun <T> List(size: Int, init: (index: Int) -> T): List<T> = MutableList(size, init)
Upvotes: 0
Reputation: 100388
CTRL + click on the +
in IDEA, you'll see that it takes you to the following function:
/**
* Returns a list containing all elements of the original collection and then all elements of the given [elements] collection.
*/
public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> {
/* ... */
}
Which means that you add all the individual elements of elements
to the receiver. That is, you'll add all T
's to the List<List<T>>
. Since List<T>
is not T
, you'll get List<Any>
as a result.
Upvotes: 2