减少嵌套循环的可能性

时间:2019-07-30 12:12:21

标签: kotlin

在所有可能的Transformations上创建列表时,我想绕开多个for循环的深层嵌套。

现在,使用此代码块:

val allTransformations = ArrayList<Transformation>().apply {
    for (moveZ in 0..4)
        for (moveY in 0..4)
            for (moveX in 0..4)
                for (rotateZ in 0..3)
                    for (rotateY in 0..3)
                        for (rotateX in 0..3)
                            add(Transformation(rotateX, rotateY, rotateZ, moveX, moveY, moveZ))
}

尽管这很简单,但我想知道Kotlin是否提供其他工具来将其写在一行中。

我想用更少的代码来检索相同的列表,看看是否会减少混乱。

2 个答案:

答案 0 :(得分:0)

可以通过以下方式调用此解决方案:

loopOverRanges(0..4, 0..4, 0..4, 0..3, 0..3, 0..3) { result ->
//    result[0], result[1], result[2], result[3], result[4], result[5]
}

这样定义:

fun loopOverRanges(
    vararg ranges: IntRange,
    function: (IntArray) -> Unit
) {
    val result = IntArray(ranges.size) { index -> ranges[index].first }

    val productOfRangeLengths = ranges
        .map { it.toList().size }
        .product()

    for (i in 0 until productOfRangeLengths) {
        function(result)

        result[0] += ranges[0].step
        for (rangeIndex in 0 until ranges.size - 1) {
            if (result[rangeIndex] == ranges[rangeIndex].last) {
                result[rangeIndex] = ranges[rangeIndex].first
                result[rangeIndex + 1] += ranges[rangeIndex].step
            }
        }
    }
}

至少可以说这是否提高了可读性值得怀疑。它消除了嵌套的需要,这对于大量范围很有用。它不能立即识别出我最初的嵌套循环。它还会隐藏命名参数,并且在检索到result [TOO_HIGH_INT]时可能会抛出IndexOutOfBounds。

这是一个有趣的小调查,但我倾向于不使用它。

答案 1 :(得分:0)

这里是一个循环的操作方法。就像用6位数字递增计数器一样。当第一个数字溢出时,携带第二个数字并重置第一个数字。等

fun loopOverRanges(a:IntRange,b:IntRange,c:IntRange,d:IntRange,e:IntRange,f:IntRange) : ArrayList<Transformation>
{

    val x = a.count() * b.count() * c.count() * d.count() * e.count() * f.count()
    val list : ArrayList<Transformation> = ArrayList()
    var rx = f.first
    var ry = e.first
    var rz = d.first
    var mx = c.first
    var my = b.first
    var mz = a.first
    for(i in 0 until x)
    {
        list.add(Transformation(rx,ry,rz,mx,my,mz))
        when{
            rx < f.last -> rx += 1
            ry < e.last -> {
                rx = f.first
                ry += 1
            }
            rz < d.last -> {
                rx = f.first
                ry = e.first
                rz += 1
            }
            mx < c.last -> {
                rx = f.first
                ry = e.first
                rz = d.first
                mx += 1
            }
            my < b.last -> {
                rx = f.first
                ry = e.first
                rz = d.first
                mx = c.first
                my += 1
            }
            mz < a.last -> {
                rx = f.first
                ry = e.first
                rz = d.first
                mx = c.first
                my = b.first
                mz += 1
            }
        }
        }
    }
    return list
}

可以简化为

fun loopOverRanges(a:IntRange,b:IntRange,c:IntRange,d:IntRange,e:IntRange,f:IntRange) : ArrayList<Transformation>
{
    data class Digit(var value :Int, val range:IntRange)
    val list : ArrayList<Transformation> = ArrayList()
    val digits = arrayOf(Digit(a.first,a),Digit(b.first,b),Digit(c.first,c),Digit(d.first,d),Digit(e.first,e),Digit(f.first,f))
    val x = digits.fold(1){acc,digit -> acc * digit.range.count() }
    for(i in 0 until x)
    {
        list.add(Transformation(digits[5].value,digits[4].value,digits[3].value,digits[2].value,digits[1].value,digits[0].value))
        val j = digits.indexOfFirst { it.value < it.range.last }
        if(j >= 0)
        {
            for(k in 0 until j )
            {
                digits[k].value = digits[k].range.first
            }
            digits[j].value += 1
        }
    }
    return list
}