空の配列を単純に削減するとスローされます:
スレッド「メイン」の例外Java.lang.UnsupportedOperationException:空の反復可能オブジェクトを減らすことはできません。
チェーン時の同じ例外:
val a = intArrayOf()
val b = a.reduce({ memo, next -> memo + next }) // -> throws an exception
val a1 = intArrayOf(1, 2, 3)
val b1 = a.filter({ a -> a < 0 }).reduce({ a, b -> a + b }) // -> throws an exception
それは削減の予想される操作ですか、それともバグですか?
回避策はありますか?
例外は正しく、reduce
は空のイテラブルまたは配列では機能しません。おそらく探しているのはfold
です。これは、開始値と、反復可能オブジェクトの各要素に連続して適用される操作を受け取ります。 reduce
はfirst要素を開始値として取るため、引数として追加の値を渡す必要はありませんが、コレクションが空でないことが必要です。
fold
の使用例:
println(intArrayOf().fold(0) { a, b -> a + b }) // prints "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
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
あなたは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