微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ASCII美术练习,但我不理解此解决方案

如何解决ASCII美术练习,但我不理解此解决方案

我正在做编码练习,并且设法解决了ASCII Art问题,虽然很长很困难,但是我做到了。 现在,我阅读了其中一种解决方案,它是用5行代码完成的! 我正在尝试理解它,但是我没有这样做,有人可以通过逐步的解释帮助我吗?

测试为您提供以下输入:

第1行:以ASCII艺术形式表示的字母的宽度L。所有字母的宽度相同。

第2行:以ASCII艺术形式表示的字母的高度H。所有字母的高度都相同。

第3行:由N个ASCII字符组成的文本T行。

以下几行:字符串ABCDEFGHIJKLMnopQRSTUVWXYZ?以ASCII艺术形式表示。

这是解决方案之一:

fun main(args : Array<String>) {
    val L = readLine()!!.toInt()
    val H = readLine()!!.toInt()
    val T = readLine()!!.toupperCase().replace("[^A-Z]".toRegex(),"[")

    val rows = (0 until H).map{readLine()!!}

    (0 until H).map{h -> T.fold(""){ a,c -> a + rows[h].substring((c-'A')*L,(c-'A')*L+L) }}.forEach{println(it)}
}

非常感谢您的帮助:)

PS。我不确定 .fold .map 是什么。

解决方法

让我们逐行分析。

val L = readLine()!!.toInt()

读取Int并将其放入变量L

val H = readLine()!!.toInt()

读取另一个Int并将其放入变量H

val T = readLine()!!
    .toUpperCase()
    .replace("[^A-Z]".toRegex(),"[")

读取一个String,将其所有字母转换为大写字符(因此a变成A),用[字符替换所有非字母的字符( [^A-Z]语法来自RegEx,而不是Kotlin),并将其放入变量T中。

val rows = (0 until H).map{ readLine()!! }

创建一个从0到H-1的数字列表,并针对每个数字将其转换为用户提供的Stringmap函数将转换类型为{{1} }转换为类型T1的列表;在这种情况下,它将T2创建的Int的列表转换为0 until H的列表,这是String)。将列表放入变量readLine()!!中。

rows

创建一个从0到H-1的列表,并为每个数字(0 until H).map{ h -> T.fold(""){ a,c -> a + rows[h].substring((c-'A')*L,(c-'A')*L+L) } } .forEach{ println(it) } 将其转换为h

在解释如何创建String之前,让我们首先分析String内部的情况。

  • fold接收者(即调用fold时在.之前的变量)是fold,因为变量StringT

  • 有两个参数,Stringa,其中ca(接收者的相同类型),Stringc(因为CharString的集合)。我们只能在集合中使用Char,这样做时,第一个参数将是其接收者的相同类型,第二个参数将是其接收者元素的相同类型。

  • 有一个隐式返回,这是参数fold与变量a的第h个元素的子字符串连接(自rows起如上所示,它是rows,该列表的任何元素都将是List<String>;还应考虑a)此列表的第一个元素位于该列表的第0位,依此类推, b)符号String是列表x[i]的第i个元素;这就是Kotlin管理列表访问的方式。

  • 此子字符串始于位置x,结束于位置(c - 'A') * L。要理解它,请将(c - 'A') * L + L视为一个数字。因此,当您编写“ A”时,实际上是在编写65。这是一个名为ASCII的约定。因此,当您执行Char时,您执行的是65-65,即0。'A' - 'A'也是如此,这意味着66-65(因为'B' - 'A'比{{1 }}(以ASCII表示),即1。由于'B'也是A,只需将其替换为表达式,最后得到一个L

但是IntInt这两个参数是什么? a只是一个循环。在第一个迭代中,c(调用fold后的括号之间的值)和a == ""(即变量fold的第一个c == T[0],即接收方)。返回一些值(在这种情况下,返回Char的值与T的子字符串连接),并在下一次迭代中返回arows[h]。在下一次迭代中,a == <returned value by a and T[0]>c == T[1]。重复循环,直到处理a == <returned value by a and T[1]>的所有元素为止。

最后,在c == T[2]中,将打印T创建的每个forEach。如果仍然有疑问,只需在屏幕上打印每个变量并尝试了解:

String

希望您能明白。


编辑:我试图将回复放入评论中,但我认为它太长了,所以我进行了编辑。

为了更好地理解,让我们定义一个函数fold,它是您的原始函数,但带有参数作为输入。如果您不知道函数是什么,请不要担心。

(0 until H).map{ h ->
    println("h=$h")
    T.fold(""){ a,c ->
        println("a=$a,c=$c")
        println("c - 'A' = ${c - 'A'}")
        a + rows[h].substring((c-'A')*L,(c-'A')*L+L)
    }
}

您可以调用以下函数:

printAscii

在这种情况下,fun printAscii(L: Int,H: Int,T: String,rows: List<String>) { (0 until H).map{ h -> T.fold(""){ a,c -> a + rows[h].substring((c-'A')*L,(c-'A')*L+L) } }.forEach{ println(it) } } 等于printAscii(L = 1,H = 2,T = "some string",rows = listOf("string1","string2")) L等于1H等于{{1} }和2等于T。现在,让我们玩吧:

"some string"

您会看到rows变量定义了listOf("string1","string2")的打印方式。

现在,让我们将printAscii(L = 1,H = 1,T = "ABCDE",rows = listOf("12345")) // the output is 12345 printAscii(L = 1,T = "AACDE",rows = listOf("12345")) // the output is 11345 printAscii(L = 1,T = "ABCBA",rows = listOf("12345")) // the output is 12321 printAscii(L = 1,T = "EDCBA",rows = listOf("12345")) // the output is 54321 printAscii(L = 1,T = "AAAAA",rows = listOf("12345")) // the output is 11111 变量更改为T

rows

现在您可以看到字符串L中的字符2printAscii(L = 2,rows = listOf("1234567890")) // the output is 1234567890 printAscii(L = 2,rows = listOf("1234567890")) // the output is 1212567890 printAscii(L = 2,rows = listOf("1234567890")) // the output is 1234563412 printAscii(L = 2,rows = listOf("1234567890")) // the output is 9078563412 printAscii(L = 2,rows = listOf("1234567890")) // the output is 1212121212 字符串中的子字符串A与字符T相关12中的rows中的子字符串与B中的子字符串T相关,依此类推。当我们将34更改为2时,rows中的每个字符都与L中大小为2的子字符串相关(如果需要,您可以尝试将T等于3,但请确保在rows的第一个元素中添加5个字符,即字符串L的大小。)

通常来说,当rows等于T时,H中的每个字符都与{{1}的第一个元素的大小1的子字符串有关} (记住这一点!)。但是如何计算哪个子字符串属于某个字符呢?

请注意,

  • TL与从rows开始的子字符串相关,L == 1与从A开始的子字符串,{ {1}}与从0开始的子字符串相关,依此类推;

  • B1与从C开始的子字符串相关,2与从L == 2开始的子字符串,{ {1}}与从A开始的子字符串相关,依此类推。

您能猜出0的模式吗?模式很简单:计算某个字母到B之间的距离(例如,2C之间的距离为1,4和{{1之间的距离}}是4)。将该距离乘以L == 3并获得子字符串的起始位置。

例如,当AA与以 4 开始的子字符串相关时。应用我们的方法,BA之间的距离为2。乘以E(即2),我们得到2 * 2 = 4 ,即子字符串的开始位置。

由于子串的大小为L(如上所述),为了获得子串的最终位置,我们可以将L == 2添加到开始位置。

根据上述信息,我们可以编写Kotlin代码。

  • 如何计算某个字符CC之间的距离?答案:A

  • 如何获取子字符串的起始位置?答案:L

  • 如何获取子字符串的结束位置?答案:L

  • 如何从L的第一个元素获取子字符串?答案:c

这是针对'A'的,但是您可以提高其价值并得出相同的结论。

对于第二个问题,您可以查看this site,特别是否定字符类部分。 Regex与Kotlin无关,但是您可以在Kotlin代码中使用Regex。

简而言之,正则表达式中的c - 'A'意味着“匹配不在A和Z之间的单个字符”,而(c - 'A') * L意味着“匹配不在0和9之间的单个字符”。如果要匹配A和Z之间的单个字符,只需删除插入符号,即(c - 'A') * L + L

话虽这么说,rows的意思是“匹配不在A和Z之间的单个字符,并将其替换为rows[0].substring((c - 'A') * L,(c - 'A') * L + L)”。为什么H == 1?还记得[^A-Z][^0-9]吗?如果您跟随火车,将会看到[A-Z]。 ASCII表中紧接.replace("[^A-Z]".toRegex(),"[")的字符是[,所以[。因此,不在A和Z之间的任何字符'B' - 'A' == 1会将表达式'E' - 'A' == 4评估为26。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。