Home Hackerrank - bon-appetit problem solution in Kotlin
Post
Cancel

Hackerrank - bon-appetit problem solution in Kotlin

For detailed problem statement, head over to the bill division problem here

From the problem definition, we get two things

  1. Element at index k should not be considered for bill computation
  2. Rest of the elements should be added and then share computed by dividing the total by two

Bear in mind that division should be done after computing the total. So, below I listed few aggregators to compute the sum from array (excluding an index). There are more ways to achieve this in kotlin. Each has slight difference and some of them are improved version of other.

1. sumBy

1
2
3
4
5
6
7
array.withIndex().sumBy { // IndexedValue<Int>
    if (it.index != k) {
        it.value
    } else {
        0
    }
}

Above creates an IndexingIterable, emits IndexedValue<Int> for each item and consumed by the sumBy function

2. sumOf

1
2
3
4
5
6
7
array.withIndex().sumOf { // IndexedValue<Int>
    if (it.index != k) {
        it.value
    } else {
        0
    }
}

sumOf follows the same footprint of sumBy. Only difference is sumOf can return different result type (ex. Double or Long instead of Int). Below snippet explains the usage of each sum function.

1
2
3
4
val totalInt = array.sumBy { it }
val totalDouble1 = array.sumBy { it.toDouble() } //Error: Type mismatch
val totalDouble2 = array.sumByDouble { it.toDouble() }
val totalDouble3 = array.sumOf { it.toDouble() }

3. foldIndexed

1
2
3
4
5
6
7
8
array.foldIndexed(0) {
    index, acc, value ->
    acc + if (index == k) {
        0
    } else {
        value
    }
}

foldIndexed function takes in a initial value and an operation lambda to operate on the element. Notice the lambda returns the accumulated value on each iteration. Unlike sum functions which need an element to operate on, here the operation owned by the us.

4. reduceIndexed

1
2
3
4
5
6
7
8
array.reduceIndexed {
    index, acc, value ->
    acc + if (index == k) {
        0
    } else {
        value
    }
}

reduceIndexed is similar to foldIndexed function, and it lacks the initial value.

There are few downsides using reduce instead of fold:

  1. If the array is empty, reduce function will throw UnsupportedOperationException

    java.lang.UnsupportedOperationException: Empty array can’t be reduced

  2. Accumulated value result type cannot be different from the array element type

Functions listed above operates on original array and computes the result. Below ones creates a filtered list out of original array, it can be used to perform operations on it.

5. filterIndexed + sum()

1
2
3
array
	.filterIndexed { index, _ -> index != k }
	.sum()

6. fold

1
2
3
array
    .filterIndexed { index, _ -> index != k }
    .fold(0) { acc, value -> acc + value }

7. reduce

1
2
3
array
    .filterIndexed { index, _ -> index != k }
    .reduce{ acc, value -> acc + value }

Solution:

Here is the complete solution to the problem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fun bonAppetit(bill: Array<Int>, k: Int, b: Int): Unit {
    val diff = b - bill.foldIndexed(0) { 
        i, total, v ->
        if (i != k) {
            total + v
        } else {
            total
        }
     }/2
    
    println(if (diff == 0) {
        "Bon Appetit"
    } else {
        diff
    })
}

Edit: I left out the loop statements here to focus on aggregators. Feel free to comment if anything else turns up, I’ll add it to the list.

This post is licensed under CC BY 4.0 by the author.