在 Kotlin 中使用带有条件的 lambda 初始化数组

Initializing an Array using lambda with conditions in Kotlin

信息

我有一个项目 class 文件如下:

class Item(var color:String, var numValue:Int, var drawableID:Int){
    init {
        color = this.color
        numValue = this.numValue
        drawableID = this.drawableID
    }
}

在主要代码中,我创建了一个默认属性包含 104 个对象的数组:

var myItemClassArray = Array(104) { Item("", -99, -99) }

我的 drawable 文件夹中也有图片,它们的 ID 在数组中 drawablesIDs:Array<Int>,它包含 53 个元素。

问题

我想分配我的项目属性,如下图所示:https://i.stack.imgur.com/wFVsn.png我可以使用下面给出的代码来解决类似的问题(有 106 个对象和 53 个可绘制对象):

        for (i in 0 until 106) {
            if (i < 13) {
                myItemClassList[i+2].color = "kirmizi"
                myItemClassList[i+2].numValue = i+1
                myItemClassList[i+2].drawableID = drawablesIDs[i+1]
            } else if (i in 13..25) {
                myItemClassList[i+2].color = "siyah"
                myItemClassList[i+2].numValue = (i+1)-13
                myItemClassList[i+2].drawableID = drawablesIDs[i+1]
            } else if (i in 26..38) {
                myItemClassList[i+2].color = "yesil"
                myItemClassList[i+2].numValue = (i+1)-26
                myItemClassList[i+2].drawableID = drawablesIDs[i+1]
            } else if (i in 39..51) {
                myItemClassList[i+2].color = "mavi"
                myItemClassList[i+2].numValue = (i+1)-39
                myItemClassList[i+2].drawableID = drawablesIDs[i+1]
            } else if (i in 52..64) {
                myItemClassList[i+2].color = "kirmizi"
                myItemClassList[i+2].numValue = (i+1)-52
                myItemClassList[i+2].drawableID = drawablesIDs[(i+1)-52]
            } else if (i in 65..77) {
                myItemClassList[i+2].color = "siyah"
                myItemClassList[i+2].numValue = (i+1)-65
                myItemClassList[i+2].drawableID = drawablesIDs[i+1-65+13]
            } else if (i in 78..90) {
                myItemClassList[i+2].color = "yesil"
                myItemClassList[i+2].numValue = (i+1)-78
                myItemClassList[i+2].drawableID = drawablesIDs[i+1-78+26]
            } else if (i in 91..103) {
                myItemClassList[i+2].color = "mavi"
                myItemClassList[i+2].numValue = (i+1)-91
                myItemClassList[i+2].drawableID = drawablesIDs[i+1-91+39]
            } else {
                myItemClassList[0].color = "sahte"
                myItemClassList[0].drawableID = drawablesIDs[0]
                myItemClassList[1].color = "sahte"
                myItemClassList[1].drawableID = drawablesIDs[0]
            }
        }

有更简洁的方法吗?

可以使用 lambda 表达式创建数组。例如:

val test = Array(28){i-> examples[i]}

使用一个 "i" 参数就可以正常工作。但是如果我想尝试这样的事情:

val test = Array(28){if(i<13)-> examples[i]}

它给我一个错误,因为它的语法是错误的。

更简单的问题

假设我们有一个数组,其中包含从 0 到 28 的数字,如下所示:

val testNumbers= Array(28){i->i}

现在我想使用 lambda 创建一个包含从 0 到 10 的数字的数组。 我该怎么做:

val player6 = Array(10){(it<10) -> testNumbers[it]} // gives an syntax error

这是一个可能的解决方案:

fun getColor(i: Int) = when (i) {
  in 0..1 -> "sahte"
  in 2..13, in 52..64 -> "kirmizi"
  in 65..77, in 13..25 -> "siyah"
  in 26..38, in 78..90 -> "yesil"
  in 39..51, in 91..103 -> "mavi"
  else -> ""
}

fun getNumValue(i: Int) = when (i) {
  in 0..1 -> -99
  in 2..13 -> i - 1
  in 13..25 -> (i - 1) - 13
  in 26..38 -> (i - 1) - 26
  in 39..51 -> (i - 1) - 39
  in 52..64 -> (i - 1) - 52
  in 65..77 -> (i - 1) - 65
  in 78..90 -> (i - 1) - 78
  in 91..103 -> (i - 1) - 91
  else -> -99
}

fun getDrawableID(i: Int) = when (i) {
  in 0..1 -> drawablesIDs[0]
  in 2..13, in 13..25, in 26..38, in 39..51 -> drawablesIDs[i - 1]
  in 52..64 -> drawablesIDs[(i - 1) - 52]
  in 65..77 -> drawablesIDs[i - 1 - 65 + 13]
  in 78..90 -> drawablesIDs[i - 1 - 78 + 26]
  in 91..103 -> drawablesIDs[i - 1 - 91 + 39]
  else -> -99
}

val myItemClassArray = Array(104) {
  Item(getColor(it), getNumValue(it), getDrawableID(it))
}

可能在不同的范围内有一些错误。

主要优点是:

  • 每个映射都可以独立测试
  • 无可变性

根据我从你的照片中收集到的信息,我做出了以下三个假设:

  • numValue 以 13 项为一组进行分组
  • 每组获得一种颜色,顺序为:kirmizi -> siyah -> yesil -> mavi,然后再次循环
  • 可绘制 ID 每 52 个项目循环一次

基于此,我想出了以下解决方案:

data class Item(var color: String = "", var numValue: Int = -99, var drawableId: Int = -99)

fun main() {
    val colors = listOf("kirmizi", "siyah", "yesil", "mavi")
    val drawableIDs = (0..52).toList()  // This is just a stub. in your case it will be your drawable lists

    val edgeCase = arrayListOf(Item("sahte", drawableId = drawableIDs[0]), Item("sahte", drawableId = drawableIDs[0]))

    val pattern = (0 until 104)
        .map { index ->  Pair(index, index / 13) }
        .map { (index, group) -> 
            Item(
                color = colors[group % 4], 
                numValue = index+1, 
                drawableId = drawableIDs[(index % 52) + 1]
            ) 
        }

    val total = pattern + edgeCase 
    total.forEach { println(it) }
}

您可以在此 kotlin playground.

上使用它

Is there a cleaner way to do this?

据我所知,您只想初始化具有 28 个空格的连续数组的前 13 个值,而将其余值保留为默认值或 null。

您的代码不起作用的原因是因为 Array 初始化器希望您 return 一个对象。 if 块本身不是 kotlin 中的表达式,因此它不会求值,因此您需要提供一个 else 分支才能使其工作。

val examples = Array(28) { if (i < 13) examples[i] else defaultExample }

这在 Kotlin documentation for control flow 中说明:

If you're using if as an expression rather than a statement (for example, returning its value or assigning it to a variable), the expression is required to have an else branch.


More simple question

在这种情况下,您可以只使用 take:

// If you don't want to modify it
val player6 = testNumbers.take(10)
                   .toTypedArray()  // Since take returns a List, you need to turn it back into an array

// If you want to modify the items
val player6 = testNumbers.take(10)
                    .map { value -> modifyNumber(value) }
                    .toTypedArray()

提示: 在 kotlin 中,如果您使用 valvar 声明构造函数参数,它们已经是您的 class 的属性,并且您不需要在 init 块中手动初始化。

/*
 * You don't need to do this:
 * class Item(var color: String, var numValue: Int, var drawableId: Int) {
 *    init {
 *      this.color = color
 *      this.numValue = numValue
 *      this.drawableId = drawableId
 *    }
 * }
 */

// Kotlin already does it for you
class Item(var color: String, var numValue: Int, var drawableId: Int)

fun main() {
    val myitem = Item("blue", 20, 100)

    println(myitem.color)
    println(myitem.numValue)
    println(myitem.drawableId)
}