我是 Kotlin 的新手,我一直在努力让这段代码将用户输入数据保存到 hashMapOf 并在它再次循环以选择波段时返回它

I'm new to Kotlin, I've been struggling to make this code save user input data to the hashMapOf and returning it when it loops again to choose a band

所以我的想法是,您可以通过选择乐队名称来查看某个乐队最喜欢的歌曲,但问题是我无法让它接受用户输入和 return 循环时的信息再次返回,以便用户稍后可以查看他新添加的歌曲。

import java.util.*

fun main(args: Array<String>) {
    fun again() {

        val favSongs = hashMapOf(
            "metallica" to "The unforgiven III",
            "disturbed" to "The vengeful one",
            "godsmack" to "Running blind",
            "lambofgod" to "The duke",
            "21savage" to "A lot"
        )
        println(
            "Choose a band to display your favorite song of it:\n(please enter the name of the band)\n" +
                "1.Metallica\n2.Disturbed\n3.Godsmack\n4.Lambofgod\n5.21savage\nEnter Here Please:"
        )
        val bandName = readln()

        when (val bandNameLower: String = bandName.lowercase(Locale.getDefault())) {
            "metallica" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
            "disturbed" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
            "godsmack" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
            "lambofgod" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
            "21savage" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
            else -> println("Enter a valid band name!")
        }

        println("Do you want to check another favorite song? (1 for Yes\n0 for No\n+ to add new favorite band & song)")
        val anotherSong = readln()
        anotherSong.toString()

        when (anotherSong) {
            "1" -> again()
            "0" -> println("Come back soon!")
        }

        if (anotherSong == "+") {
            println("Enter the name of the band:")
            val newBandName: String = readln()
            println("What's your favorite song for $newBandName")
            val newFavSong: String = readln()
            favSongs["$newBandName"] = "$newFavSong"
            again()
        }
    }
    again()
}

如@cactustictacs 所述,您需要让 favSongs 地图位于 again() 之外,这样它就不会在您每次调用该函数时都被重置。

此外,为了使添加歌曲流程正常工作,您需要进行一些调整。我在这里更新了代码(有一些评论希望能有所帮助):

fun main() {
    // I moved this out of the again() function, plus changed it to Kotlin's MutableMap class
    val favSongs = mutableMapOf(
        "Metallica" to "The unforgiven III",
        "Disturbed" to "The vengeful one",
        "Godsmack" to "Running blind",
        "LambofGod" to "The duke",
        "21Savage" to "A lot"
    )

    fun again() {
        // This now programmatically displays all your artists and songs rather than having them hard-coded.
        println(
            "Choose a band to display your favorite song of it:\n(please enter the name of the band)\n" +
                favSongs.keys
                    .mapIndexed { index, bandName -> "${index + 1}. $bandName" }
                    .joinToString("\n")

        )
        // The previous toString() call didn't change the original value so I removed it.
        // Plus, bandName is already a string so no need to convert.
        val bandName = readln()


        // I took this approach since we're always doing the same thing (get song by band name)
        // Also, this allows the entry to be upper or lower case, we don't care.
        val favoriteSong = favSongs.entries.firstOrNull { (band, _) ->
            band.equals(bandName, ignoreCase = true)
        }?.value

        if (favoriteSong != null) {
            println("Your favorite song of $bandName is: $favoriteSong")
        } else {
            println("Enter a valid band name!")
        }

        println("Do you want to check another favorite song?\n(1 for Yes, 0 for No, + to add new favorite band & song)")

        val anotherSong = readln()

        // The "+" scenario can be included in the when { ... } block without issue.
        when (anotherSong) {
            "1" -> again()
            "0" -> println("Come back soon!")
            "+" -> {
                println("Enter the name of the band:")
                val newBandName: String = readln()
                println("What's your favorite song for $newBandName")
                val newFavSong: String = readln()
                favSongs[newBandName] = newFavSong
                again()
            }
        }
    }
    again()
}

(这比我想象的要长,因为我开始 运行 了解你正在做的事情的复杂性 - 我知道你是新手,我希望这不会让人不知所措,但有一些棘手的问题需要处理的事情!)

好的,这是组织循环的一种方法:

import java.util.Locale

val favSongs = mutableMapOf(
    "metallica" to "The unforgiven III",
    "disturbed" to "The vengeful one",
    "godsmack" to "Running blind",
    "lambofgod" to "The duke",
    "21savage" to "A lot"
)

fun main() {
    var option: String
    // loop until the user types "0" in the options
    do {
        displayFav()
        // show the options menu, and get the result
        option = showOptions()
        // if the user typed "+" we need to let them add a new fav before we loop
        if (option == "+") addNewFav()
    } while (option != "0")

    // You can print this message when you leave the loop
    println("Come back soon!")
}

fun displayFav() {
    println(
        "Choose a band to display your favorite song of it:\n(please enter the name of the band)\n" +
                "1.Metallica\n2.Disturbed\n3.Godsmack\n4.Lambofgod\n5.21savage\nEnter Here Please:"
    )
    val bandName = readln()

    when (val bandNameLower: String = bandName.lowercase(Locale.getDefault())) {
        "metallica" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
        "disturbed" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
        "godsmack" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
        "lambofgod" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
        "21savage" -> println("Your favorite song of $bandName is: " + favSongs[bandNameLower])
        else -> println("Enter a valid band name!")
    }
}

fun showOptions(): String {
    println("Do you want to check another favorite song?")
    println("(1 for Yes\n0 for No\n+ to add new favorite band & song)")
    return readln()
}

fun addNewFav() {
    println("Enter the name of the band: ")
    val newBandName: String = readln()
    println("What's your favorite song for $newBandName: ")
    val newFavSong: String = readln()
    favSongs[newBandName] = newFavSong
}

main 中的 while 循环允许程序保持 运行 直到遇到某些条件,例如用户在这种情况下输入“退出”命令。所以循环基本上得到他们的输入,并检查他们最后输入的内容。如果它是 "0" 它退出 - 任何其他 并且它再次循环(即这是默认值,就像他们输入 "1"

我已将逻辑分解为几个不同的函数,因此更容易查看 main 并了解它的整体情况 运行。每个任务的详细信息都在不同的函数中,您可以调整每个任务中发生的事情,而不必担心其他任务。


举个例子 - 您的代码现在无法正常工作,因为您正在硬编码歌曲菜单以及它将接受的名称列表!即使您可以将歌曲添加到地图,但在显示乐队或检查有效名称时您并没有使用地图。

你可以这样做:

fun displayFav() {
    println("Choose a band to display your favorite song of it:\n(please enter the name of the band)\n")
    favSongs.keys
        .mapIndexed { index, bandName -> "${index + 1}. $bandName\n" }
        .forEach { println(it) }
    val bandName = readln()

    val favSong = favSongs[bandName]
    if (favSong != null) println("Your favorite song of $bandName is: $favSong")
    else println("Enter a valid band name!")
}

所以现在,我们正在获取地图的 keys(乐队名称)并使用 mapIndexed 将它们(连同它们在地图中的索引)转换为编号列表项目。我们可以获取用户输入的内容,尝试从地图中获取它,如果该乐队存在,我们将获取歌曲 - 否则我们将获取 null 并告诉他们输入有效名称。


但是 这就是问题所在 - 您正在使用 lowercase 创建 case-insensitive 查找,对吗?没关系,但是您不能将波段名称用作 table 中的键,并且不能将它们小写(用于查找) 正确大写(用于显示)。当用户添加自己的 band 时,您可以将名称小写以存储它,但这样您就失去了格式。

您有两个选择:

  • 将小写名称存储为键,映射到包含正常格式名称(用于显示)的数据结构(如基本数据class)和最喜欢的歌曲
  • 将正常格式的名称存储为键,映射到最喜欢的歌曲,但通过遍历映射中的每个条目查找乐队,将其键小写并将其与用户的小写输入进行比较

我认为第一个选项更好,但这已经足够长了,并且已经涉及所有这些其他切线概念,所以我将只做“遍历条目”的事情,这样就不会太多了变化:

fun displayFav() {
    println("Choose a band to display your favorite song of it:\n(please enter the name of the band)\n")
    favSongs.keys
        .mapIndexed { index, bandName -> "${index + 1}. $bandName\n" }
        .forEach { println(it) }
    val bandName = readln().lowercase(Locale.getDefault())

    val favSong = favSongs.entries
        .firstOrNull { (k, _) -> k.lowercase(Locale.getDefault()) == bandName}
        ?.value
    if (favSong != null) println("Your favorite song of $bandName is: $favSong")
    else println("Enter a valid band name!")
}

现在你可以正确地存储波段名称,当涉及到查找比较时,所有的东西都是小写的。这不是最有效的做事方式(并且使用数据 classes 可以让您根据需要轻松添加更多数据,比如相册名称),但对于小地图来说,这并不重要。

我也不会像那样处理用户选项输入,但这已经足够了!