如何在空的Kotlin阵列上调用reduce?

时间:2016-02-26 20:11:29

标签: reduce kotlin

简单地减少空数组将抛出:

线程“main”中的异常java.lang.UnsupportedOperationException:无法减少空迭代。

链接时的相同例外:

<script>
var tableobj = [
        {table:{binding:""}},
        {thead:{binding:"0"}},
        {tbody:{binding:"0"}},
        {tr:{binding:"00"}},
        {th:{binding:"000"}},
        {th:{binding:"000"}},
        {th:{binding:"000"}}
];

function init(){
    //GENERATE HTML & BIND PROPERTIES
    var elementArray = generate(tableobj);
    console.log(elementArray);

    //ASSEMBLE THE TABLE --- example: elementArray[0].appendChild(thead) 
    var elementAssembly = assemble(elementArray);

    console.log(elementAssembly);
    console.log(elementAssembly[0]);
    //OUTPUT
    //TABlE->THEAD
    //TABlE->THEAD
    //TABlE->THEAD->TR
    //TABlE->THEAD->TR->TH
    //TABlE->THEAD->TR->TH
    //TABlE->THEAD->TR->TH
}
function assemble(o){   
    o.forEach(function(ele){
        var position = ele.position.replace(/0/g,"[0]");
        var position = ele.position.split('');
        if(ele.position.length > 0){
            //WHERE MY QUESTION LIES....
            var parent = o[position];
            parent.appendChild(ele);
        }
    });
    return o;
};
function generate(o){
    var struct = o.map(function(ele,i){
        var element = document.createElement(Object.keys(ele));
        for(prop in ele){
            var key = Object.keys(ele[prop]);
            key.forEach(function(attr){
                switch(attr){
                    case "binding":
                        Object.defineProperty(element,'position',{
                            value: ele[prop][attr]
                        });
                        break;          
                }
            });         
        }
        return element;
    })
    return struct;
}

//ONLOAD TRIGGER INIT
document.addEventListener('DOMContentLoaded', init);
</script>

是减少的预期操作还是错误?

有没有解决方法?

4 个答案:

答案 0 :(得分:42)

异常是正确的,reduce对空的iterable或数组不起作用。你可能正在寻找的是fold,它接受​​一个起始值和一个对迭代的每个元素连续应用的操作。 reduce first 元素作为起始值,因此不需要将其他值作为参数传递,但要求集合不为空。

fold的使用示例:

println(intArrayOf().fold(0) { a, b -> a + b })  // prints "0"

答案 1 :(得分:1)

public inline fun <S, T : S> List<T>.reduceRightDefault(defaultIfEmpty: S, operation: (T, acc: S) -> S): S {
    return if (isEmpty()) defaultIfEmpty
    else reduceRight(operation)
}

用法:

val result = listOf<Boolean>().reduceRightDefault(false) { first, second -> first && second}

println("result $result")//result false

答案 2 :(得分:0)

我只想为无法使用fold(...)的情况添加更多通用方法。因为,为了使用fold,您需要能够表达一些初始值。

someIterable
    .filter{ TODO("possibly filter-out everything") }
    .takeIf{ it.isNotEmpty() }
    ?.reduce{ acc, element -> TODO("merge operation") }
    ?: TODO("value or exception for empty")

使用这种方法,在集合为空的情况下,reduce将不会执行,因为takeIf会将其转换为null。最后,在这种情况下,我们可以使用elvis运算符表达一些值(或引发异常)。

您的示例:

intArrayOf(1, 2, 3)
    .filter({ a -> a < 0 })
    .takeIf{ it.isNotEmpty() }
    ?.reduce({ a, b -> a + b })
    ?: 0

答案 3 :(得分:0)

您可以使用foldRight:

println(listOf("1", "2", "3")
    .filter { "not found" == it }
    .foldRight("") { a, b -> a + b }) // prints: ""

println(listOf("1", "2", "3")
    .filter { "not found" != it }
    .foldRight("") { a, b -> a + b }) // prints: "123"

或您的情况:

val a = intArrayOf()
val b = a.foldRight(0) { memo, next -> memo + next } // b == 0
val a1 = intArrayOf(1, 2, 3)
val b1 = a.filter { a -> a < 0 }.foldRight(0) { a, b -> a + b } // b1 == 0