使用哈希图和匹配值

Using hashmaps and matching values

我重新编写了一些代码,使其更清楚我的范围。希望现在更容易理解了!我还添加了代码内说明以使其更易于理解!本质上,我想根据哈希图中相同的年龄来匹配 2 个哈希图。当我向集合中添加新年龄时,这也应该有效!

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!")
        }


    }

}

在这里,我需要能够比较所有男性的年龄 (allMen) 和所有女性的年龄 (allWomen) 并且只打印出与两个系列中的年龄相匹配的女性的年龄。 示例:

  1. 我将“Smith”- 20 - 输入到男士哈希图中。这应该给我:来自 allWomen 的“Rebecca,20”。因为这 2 个在两个系列中只有相同的匹配年龄。 我怎样才能做到这一点?

(评论已经阐明,所需的输出是从年龄到该年龄段所有男性和女性姓名的合并映射。​​)

我能看到的最简单的解决方案是 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 })

这给出了一张地图:

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

它使用 groupBy() 的 two-lambda 形式,让您也可以转换值(否则它们也会成对,包括年龄)。

(你会注意到我添加了一个相同年龄的男人和一个女人,以说明效果。我还使用了中缀函数 to,它正是为此而创建的例。)


但是这种方法有一个问题:如果一个男人和一个女人有相同的名字(例如“Pat”),它就无法处理。如果有,那么它会从结果中省略其中之一。 (这可能不是你关心的问题,因为你使用的地图已经防止了两个男人或两个女人同名的可能性。)

要解决此问题,您可以将映射条目转换为序列,连接它们,然后将其分组,您也可以在一行中执行此操作:

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 })

给予:

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

要处理两个同名的男人或两个女人,您首先需要不同的数据结构。例如,您可以创建一个简单的数据 class 来代表一个人,而不是匿名键和值:

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

然后您可以将数据创建为简单列表:

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))

(你可能认为集合会更合适——但这不能处理两个同名 年龄的人,如果很少见,这总是可能的。如果没有固有的人员排序,这似乎并不自然,但至少他们会处理所有情况。此外,我添加了第二个“鲍勃”,与第一个年龄不同,以说明。)

然后您可以将它们与类似的 one-liner:

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

给予:

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

这不仅是最简单的版本,而且更易于阅读(具有有意义的字段 agename 而不是之前的 keyvalue),并且可能更容易维护和调试。