Kotlin 地图不适用于字符串列表

Kotlin map not working with List of String

我一直在编写代码,我必须在其中生成目标字符串的所有可能方式。我正在使用下面提到的代码。

打印报表:

println("---------- How Construct -------")
    println("${
        window.howConstruct("purple", listOf(
            "purp",
            "p",
            "ur",
            "le",
            "purpl"
        ))
    }")

函数调用:

fun howConstruct(
        target: String,
        wordBank: List<String>,
    ): List<List<String>> {

        if (target.isEmpty()) return emptyList()

        var result = emptyList<List<String>>()

        for (word in wordBank) {
            if (target.indexOf(word) == 0) {    // Starting with prefix
                val substring = target.substring(word.length)
                val suffixWays = howConstruct(substring, wordBank)
                val targetWays = suffixWays.map { way ->
                    val a = way.toMutableList().apply {
                        add(word)
                    }
                    a.toList()
                }

                result = targetWays

            }
        }

        return result
    }

预期输出:- [['purp','le'],['p','ur','p','le']]

当前输出:- []

您的代码几乎可以正常工作;只需要做一些小的改动就可以得到所需的输出:

  • 如果目标为空,return listOf(emptyList()) 而不是 emptyList()
  • 使用 add(0, word) 代替 add(word)

这些更改中的第一个是重要的。您的函数 return 是一个匹配列表;由于每个匹配项本身都是一个字符串列表,因此它 return 是一个字符串列表列表。一旦你的代码匹配了整个目标并最后一次调用自己,它 return 一个空列表——即没有匹配——而不是一个列表 包含 一个空列表——这意味着一场比赛,没有剩余的字符串。

第二个更改只是修复了每个匹配项中字符串的顺序,这是相反的(因为它在 returned 后缀匹配之后附加了前缀 。 =30=]


但是,还有许多其他方法可以改进代码。与其单独列出它们,不如给出一个替代版本可能更容易:

fun howConstruct(target: String, wordBank: List<String>
    ): List<List<String>>
= if (target == "") listOf(emptyList())
else wordBank.filter{ target.endsWith(it) } // Look for suffixes of the target in the word bank
            .flatMap { suffix: String ->
                howConstruct(target.removeSuffix(suffix), wordBank) // For each, recurse to search the rest
                    .map{ it + suffix } } // And append the suffix to each match.

这与您的代码几乎完全相同,只是它从字符串的结尾(匹配后缀)而不是从开头进行搜索。结果是一样的;主要好处是将后缀字符串附加到部分匹配列表(使用 +)比添加前缀(如您所见,这非常混乱)更简单。

然而,它更简洁,主要是因为它使用了函数式风格——特别是,它使用 filter() 来确定哪些单词是有效的后缀,并使用 flatMap() 来整理列表递归地匹配每个匹配项,以及 map() 将后缀附加到每个匹配项(就像您的代码一样)。这避免了循环列表、创建列表和添加列表的所有业务。因此,它不需要处理可变列表或变量,避免了一些混淆和错误的来源。

为了简单起见,我将其写成表达式主体(使用 = 而不是 { … })。我发现对于短函数来说,这更简单、更清晰——不过,这个函数是关于极限的。它可能适合作为 String 的扩展函数,因为它有效地 return 转换字符串,没有任何 side-effects — 不过,这往往在短函数上效果最好。

还有一些小调整。使用 startsWith()endsWith() 而不是 indexOf() 更简单也更有效; removePrefix()removeSuffix() 可以说比 substring() 更清晰;我发现 == ""isEmpty().

更清晰

(此外,名称 howConstruct() 并没有很好地描述结果,但到目前为止我还没有想出更好的东西......)

其中许多更改当然是个人喜好问题,我相信其他开发人员会以许多其他方式编写它!但我希望这能提供一些想法。