Kotlin 中 DynamicArray 的自定义打印打印出意外的结果 更新

问题描述

我有一个简单的场景,我有 Kotlin 类 DynamicArray.kt:

class DynamicArray(size: Int) {

    private var numArray: IntArray
    private var count: Int = 0

    init {
        if (size <= 0)
            throw IllegalArgumentException("Invalid value for array size")    
        numArray = IntArray(size)
    }

    fun insert(item: Int) {
        if (numArray.size == count){

            // Create newArray with double size
            val newArray = IntArray(count * 2)

            // copy old to new
            for ((index,i) in numArray.withIndex()){
                newArray[index] = i
            }

            // assign newArray to old
            numArray = newArray

        }
        numArray[count++] = item
    }

    fun print(): String {
        val arrayAsstring = StringBuilder()
        arrayAsstring.append("[")
        for ((index,i) in numArray.withIndex()){
            arrayAsstring.append(i)
            if (index != (count - 1)){
                arrayAsstring.append(",")
            }
        }
        arrayAsstring.append("]")
        return arrayAsstring.toString()
    }
}

还有一个简单的 Main.kt 类,它只有:

fun main(args: Array<String>) {
    val array = DynamicArray(3)

    array.insert(1)
    array.insert(2)
    array.insert(3)

    println(array.print())

}

当 DynamicArray 的 sizeitems 相等时,上面的代码完美运行

[1,2,3]

但是当我们插入更多项目时,初始大小例如:

fun main(args: Array<String>) {
    val array = DynamicArray(3)

    array.insert(1)
    array.insert(2)
    array.insert(3)
    array.insert(4)

    println(array.print())

}

它打印出奇怪的值,例如:

[1,3,40,]

更新

如果我将打印方法更改为:

fun print(): String {
        return numArray.contentToString() // using built-in method
}

它仍然打印:

[1,4,0]

无法找出导致此问题的原因。

解决方法

首先,让我们看看如何找出问题所在。

调试的技术有很多,但到目前为止最有用的就是简单地打印出来。为了缩小问题的范围,能够在每个点查看程序的状态(在本例中为 DynamicArray 的内容)真的非常有用。

您希望能够做的是添加一行,例如:

println("Point A: $array")

...在每次调用 insert() 之前和之后。麻烦的是,它只是打印如下内容:

Point A: DynamicArray@63947c6b

...这是因为 DynamicArray 不会覆盖 toString()。您可以改为调用您的 print() 方法 - 但您不知道错误是否在那里。

如果 DynamicArray 是 data class,您将自动获得闪亮的 toString() 实现。但是这个类并不适合作为数据类(并且需要很多其他更改)。但是没有什么能阻止你自己写,例如:

override fun toString() = "DynamicArray(count=$count,numArray=[${numArray.joinToString()}])"

有了它,您就可以添加大量调试输出。例如:

Start: DynamicArray(count=0,numArray=[0,0])
Inserted 1: DynamicArray(count=1,numArray=[1,0])
Inserted 2: DynamicArray(count=2,2,0])
Inserted 3: DynamicArray(count=3,3])
Inserted 4: DynamicArray(count=4,3,4,0])
Inserted 5: DynamicArray(count=5,5,0])
[1,50,]

由此,问题出在哪里变得更加清晰了!您可以看到 countnumArray 都设置正确。所以问题一定出在您的 print() 方法中。

我不会在这里给出最终的解决方案,因为我认为它会帮助你更多地自己解决其余的问题;我希望这已经给了你足够的开始来做到这一点。 (如果你想要一个提示,请考虑它打印了多少个数字,以及它把逗号放在哪里。)

,

当插入不适合的新项目时,数组的大小加倍。这意味着内部数组的大小可能大于动态数组的虚拟大小。

要仅显示添加的元素,您应该从 0 到 count 迭代,而不是迭代整个数组。

手动追加的示例:

fun print(): String {
    val builder = StringBuilder()
    // Iterate over *inserted* indices only
    for (i in 0 until count) {
        if (builder.isNotEmpty()) {
            builder.append(",")
        }
        builder.append(numArray[i])
    }
    builder.insert(0,"[")
    builder.append("]")
    return builder.toString()
}

使用内置函数的替代方法:(这会创建一个中间列表)

fun print(): String {
    // get a List of added elements
    val content = numArray.take(count)
    // convert the list to a string
    return content.joinToString(prefix = "[",postfix = "]")
}
,

即使计数较少,您的打印方法也会迭代所有元素,因此在打印字符串后附加零。对代码进行最少更改的简单解决方案是,如果索引大于计数,则中断循环

fun print(): String {
    val arrayAsString = StringBuilder()
    arrayAsString.append("[")
    for ((index,i) in numArray.withIndex()){
        if(index>=count) break;    // NEW condition
        arrayAsString.append(i)
        if (index != (count - 1)){
            arrayAsString.append(",")
        }
    }
    arrayAsString.append("]")
    return arrayAsString.toString()
}

这是使用 Kotlin 内置功能的 DynamicArray 类的更简单代码

class DynamicArray(size: Int) {

  private var numArray: IntArray
  private var count: Int = 0

  init {
    require(size>0) { "Invalid value for array size" }
    numArray = IntArray(size)
  }

  fun insert(item: Int) {
    if (numArray.size == count) {
      numArray = numArray.copyInto(IntArray(count * 2))
    }
    numArray[count++] = item
  }

  fun print() = numArray.take(count).joinToString(",","[","]")
}