Home > Net >  Using hashmaps and matching values
Using hashmaps and matching values

Time:05-31

I re-made my code a bit to make it more clear of my scope. Hope it's more understandable now! I also added in-code instructions to make it more understandable! Essentially I want to match the 2 hashmaps based on the same ages in the hashmaps. This should also work when I add new ages to the collections!

fun main() {
    val allMen = AllMenInfo2()
    allMen.takeUserName()

}

open class AllMenInfo2 {

    // This code contains pre-made keys-value pairs for men respective women in a Class.
    // These represent name and age!
    // I want to add a new MAN with a name and an age to the hashmap of allMenInfo.

    val allMen = hashMapOf(Pair("Bob", 18), Pair("Ken", 21), Pair("Jerry", 25))
    val allWomen = hashMapOf(Pair("Alice", 19), Pair("Rebeca", 20), Pair("Olivia", 27))


    // This takes userInput of name.

    open fun takeUserName() {
        println("Enter your name!")
        val userName = readLine() ?: ""
        val names = userName
        println(allMen)

        // This takes userinput of age and adds both name and age to the hashmap of allMenInfo!

        try {
            println("Please enter your age!")
            val ageOfUsers = readLine() ?: ""
            val ages = ageOfUsers.toInt()
            allMen.put(names, ages)


        } catch (E: Exception) {
            println("Invalid number/name, please try again!")
        }


    }

}

Here I need to be able to compare all the men's ages (allMen) to all the women's ages (allWomen) and only printout the ages of women who matches the ages in both collections. Example:

  1. I input "Smith" - 20 - to the men's hashmap. This should give me: "Rebecca, 20" from allWomen. Since those 2 only has the same matching age's across both collections. How can I achieve this?

CodePudding user response:

(Comments have clarified that the desired output is a merged map from age to the names of all men and women with that age.)

The simplest solution I can see is a one-liner:

val allMen = mapOf("Bob" to 18, "Ken" to 21, "Jerry" to 25, "TwinM" to 22)
val allWomen = mapOf("Alice" to 19, "Rebeca" to 20, "Olivia" to 27, "TwinF" to 22)

val merged = (allMen   allWomen).entries.groupBy({ it.value }, { it.key })

That gives a map of:

{18=[Bob], 19=[Alice], 20=[Rebeca], 21=[Ken], 22=[TwinM, TwinF], 25=[Jerry], 27=[Olivia]}

It uses the two-lambda form of groupBy() that lets you transform the values too (else they'd be pairs including the age too).

(You'll note that I've added a man and a woman with the same age, to illustrate the effect. I've also used the infix function to, which was created for exactly this case.)


There's a problem with this approach, though: it doesn't cope if a man and a woman have the same name (e.g. "Pat"). If there were, then it would omit one of them from the result. (That probably isn't a concern for you, given that the maps you're using already prevents the possibility of two men with the same name, or two women.)

To fix this, you could convert the map entries to sequences, concatenate them, and then group that, which you can also do in one line:

val allMen = mapOf("Bob" to 18, "Ken" to 21, "Jerry" to 25, "TwinM" to 22, "Pat" to 30)
val allWomen = mapOf("Alice" to 19, "Rebeca" to 20, "Olivia" to 27, "TwinF" to 22, "Pat" to 31)

val merged = (allMen.asSequence()   allWomen.asSequence()).groupBy({ it.value }, { it.key })

Giving:

{18=[Bob], 19=[Alice], 20=[Rebeca], 21=[Ken], 22=[TwinM, TwinF], 25=[Jerry], 27=[Olivia], 30=[Pat], 31=[Pat]}

To handle two men or two women with the same name, you'd need a different data structure to start with. For example, instead of anonymous keys and values, you could create a simple data class to represent a person:

data class Person(val name: String, val age: Int)

You could then create your data as simple lists:

val men = listOf(Person("Bob", 18), Person("Ken", 21), Person("Jerry", 25), Person("TwinM", 22), Person("Pat", 30), Person("Bob", 17))
val women = listOf(Person("Alice", 19), Person("Rebecca", 20), Person("Olivia", 27), Person("TwinF", 22), Person("Pat", 31))

(You might think that sets would be more suitable — but that wouldn't handle two people with the same name and age, which is always possible if rare. Lists may not seem natural if there's no inherent ordering of people, but at least they'll handle all cases. Also, I've added a second "Bob", with a different age from the first, to illustrate.)

You could then merge them with a similar one-liner:

val personsByAge = (men   women).groupBy({ it.age }, { it.name })

Giving:

{17=[Bob], 18=[Bob], 19=[Alice], 20=[Rebecca], 21=[Ken], 22=[TwinM, TwinF], 25=[Jerry], 27=[Olivia], 30=[Pat], 31=[Pat]}

Not only is this the simplest version, it's also easier to read (with meaningful fields age and name instead of the previous key and value), and is probably easier to maintain and debug.

  • Related