counting pairs in a list

1.1k views Asked by At

I've recently started on HackerRank and I'm attempting "Sales by Match". I've arrived at a solution I'm content with in terms of exploiting Kotlin's function programming capabilities. However, I'm not getting the expected answer...

Problem summary:

Given an Array: -> find and return the total number of pairs.

i.e:

input -> [10, 20, 20, 10, 10, 30, 50, 10, 20]

number of pairs -> 3


here is my code and some comments to explain it:

fun sockMerchant(n: Int, pile: Array<Int>): Int{
    var count = 0
    mutableMapOf<Int, Int>().withDefault { 0 }.apply {
        // the [attempted] logic behind this piece of code here is 
        // that as we iterate through the list, the 'getOrPut()'
        // function will return either the value for the given [key]             
        // or throw an exception if there is no such key
        // in the map. However, since our map was created by 
        // [withDefault], the function resorts to its `defaultValue` <-> 0
        // instead of throwing an exception.
        for (e in values) {
            // this simplifies our code and inserts a zero [+1] where needed.
            // if (key exists)
            //      // return its associated value and MOD it:
            //      case: even  -> increment counter
            //            else  -> do nothing
            // else if (key dne)
            //      // insert default value <-> [0] + 1
            //              ....
            //              ....
            //              ....
            if (getOrPut(e, { getValue(e) + 1 } ) % 2 == 0) count++
        }
    }
    return count
}


fun main(args: Array<String>) {
    val scan = Scanner(System.`in`)
    val n = scan.nextLine().trim().toInt()
    val ar = scan.nextLine().split(" ").map{ it.trim().toInt() }.toTypedArray()
    val result = sockMerchant(n, ar)
    println(result)
}

-- Any help or tips would go a long way here:)

2

There are 2 answers

0
Jonathan Schoreels On BEST ANSWER

I modified it a bit to be more easily testable, but here is the fixes :

import java.util.*

fun sockMerchant(n: Int, pile: Array<Int>): Int{
    var count = 0
    mutableMapOf<Int, Int>().withDefault { 0 }.apply {
        // the [attempted] logic behind this piece of code here is
        // that as we iterate through the list, the 'getOrPut()'
        // function will return either the value for the given [key]
        // or throw an exception if there is no such key
        // in the map. However, since our map was created by
        // [withDefault], the function resorts to its `defaultValue` <-> 0
        // instead of throwing an exception.
        for (e in pile) {
            // this simplifies our code and inserts a zero [+1] where needed.
            // if (key exists)
            //      // return its associated value and MOD it:
            //      case: even  -> increment counter
            //            else  -> do nothing
            // else if (key dne)
            //      // insert default value <-> [0] + 1
            //              ....
            //              ....
            //              ....
            println(e)
            put(e, getValue(e) + 1)
            if (getValue(e) % 2 == 0) count++
            println(entries)
        }
    }
    return count
}


val n = 5
val ar = "10 10 10 10 20 20 30 40".split(" ").map{ it.trim().toInt() }.toTypedArray()
val result = sockMerchant(n, ar)
println(result)

Output :

10
[10=1]
10
[10=2]
10
[10=3]
10
[10=4]
20
[10=4, 20=1]
20
[10=4, 20=2]
30
[10=4, 20=2, 30=1]
40
[10=4, 20=2, 30=1, 40=1]
3
Pair.kts:3:18: warning: parameter 'n' is never used
fun sockMerchant(n: Int, pile: Array<Int>): Int{
                 ^

Process finished with exit code 0

Explanation :

  • You looped over "values", which is at start empty, so you never did anything with your code
  • Even when looping over pile, your incrementation logic didn't go above 1, so the condition was never satisfied and the count was never incremented.

But the main reasoning behind was correct.

0
Todd On

I was able to do this by grouping the numbers together, taking the resulting lists, and summing how many pairs each one contains:

fun sockMerchant(n: Int, pile: Array<Int>): Int =
    pile.groupBy { it }.values.sumBy { it.size / 2 }

After we do pile.groupBy { it }, we have this structure:

{10=[10, 10, 10, 10], 20=[20, 20, 20], 30=[30], 50=[50]}

We take the values, and sum by each of their size dividing by 2. This will round half-pairs down to 0 and full pairs to 1 each.

Note: I am not entirely clear what the purpose of n is in this case.