Sum of Array

How to find sum of an elements of an array containing integers and IntArrays?

If possible please solve this question using Kotlin

Here you are.

val array: Array<Any> = ...
val sum = array.flatMap<Any,Int>{
  when(it){
    is Int -> intArrayOf(it)
    is IntArray -> it
    else -> error()
  }
}.sum()

Of course, it works only if there are only arrays and integers in the top level array. If it is possible for top level array to contain arrays of arrays, one needs to add a recursive clause to when.

1 Like

This should solve your question. This function accepts arrays of any type but if it finds anything that is not an Int it will throw an exception. You can replace the error("Not an integer: $it") with listOf(0) if you want to ignore non-integers (treat them as 0) without crashing every time.

fun main(args: Array<String>) {
    smartSum(arrayOf(1, 2, 3, arrayOf(4, 5), 6)) // returns 21
    smartSum(arrayOf(1, 2, arrayOf(arrayOf(3, 4), 5), 6)) // returns 21
    
    // More examples
    smartSum(arrayOf(1, arrayOf(2, arrayOf(3, arrayOf(4, arrayOf(5, 6)))))) // returns 21
    smartSum(arrayOf("Hello", "world")) // Throws java.lang.IllegalStateException: Not an integer: Hello
}

fun smartSum(array: Array<Any>): Int {

    fun Array<*>.flattenToInt(): Iterable<Int> = flatMap {
        @Suppress("UNCHECKED_CAST")
        when (it) {
            is Int -> listOf(it)
            is Array<*> -> (it as? Array<Int>)?.toList() ?: it.flattenToInt()
            else -> error("Not an integer: $it")
        }
    }

    return array.flattenToInt().sum()
}
2 Likes

That solution creates lots of unnecessary objects. Simpler solution:

val sum = array
        .sumBy {
            when(it) {
                is Int -> it
                is IntArray -> it.sum()
                else -> error()
            }
        }
2 Likes

Your code won’t work with nested or mixed arrays like:

arrayOf(1, 2, arrayOf(arrayOf(3, 4), 5), 6)

Which were not allowed under the original problem statement

Not in the way the question was stated here, but if you follow the link to the coding challenge it also allows for nested arrays :wink:

It in fact could be also adjusted with recursive clause like that:

fun Array<*>.sumByInt(): Int{
  return this.sumBy {
            when(it) {
                is Int -> it
                is IntArray -> it.sum()
                is Array<*> -> it.sumByInt() // fix by @dalewking
                else -> error("some error message")
            }
        }
}

val result = array.sumByInt()

I like it better then my solution. Kotlin has a lot of convenient extensions and I missed sumBy which has inlined for-loop. I am thinking a lot in terms of Java 8 lambdas, which work different from kotlin inlined lambdas. In Java 8 objects are not created when one calls lambda since it utilized invokedynamic which is still not available in kotlin. But in any case, sumBy looks better and avoids number wrapping in array.

1 Like

Nitpick. That should be:

is Array<*> -> it.sumByInt()

Frankly, all I was doing was refactoring @darksnake’s code which did not support it either which he acknowledged.


Your code is not working.

It would work this way:

    val array: Array<Any> = arrayOf(1,2, intArrayOf(3,4,5),3)
    val sum = array.flatMap<Any,Int>{
      when(it){
        is Int -> intArrayOf(it).asIterable()
        is IntArray -> it.asIterable()
        else -> error("this is error")
      }
    }.sum()

The initial array should contain only IntArrays as internals, otherwise you need a recursive clause.
The solution, proposed by @dalewking with addition of recursion works in case of arrayOf() and looks better.

Thanks