编写嵌套的
for
循环以每行产生以下输出48个字符宽:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~+~~+~~+~~+~~+~~+~~+~~+~~+~~+~~+~~+~~+~~+~~+~~+~
+~++~++~++~++~++~++~++~++~++~++~++~++~++~++~++~+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这是我的主意,但我想那是多余的。如果是这样,如何在这里最小化冗余?顺便说一下,我的输出是正确的。
public class Exercises {
public static void main (String[] args){
for (int i = 1; i <= 4; i++){
for (int j = 1; j <= 12; j++){
System.out.print("~");
}
}
System.out.println();
System.out.print("~");
for (int i = 1; i <=15; i++){
System.out.print("+~~");
}
System.out.println("+~");
System.out.print("+~");
for (int i = 1; i <= 15; i++){
System.out.print("++~");
}
System.out.println("+");
for (int i = 1; i <= 4; i++){
for (int j = 1; j <= 12; j++){
System.out.print("~");
}
}
}
}
#1 楼
for (int i = 1; i <= 4; i++){
for (int j = 1; j <= 12; j++){
System.out.print("~");
}
}
System.out.println();
可以很容易地是:
for (int i = 0; i < 48; i++) {
System.out.print('~');
}
System.out.println();
一些编辑:
改进的格式:从
){
到) {
简化为一个从
for
到0
的47
循环(从0
开始,运行到小于48
)打印单个字符而不是一个字符包含一个字符的字符串以提高性能
此:
System.out.print("~");
for (int i = 1; i <=15; i++){
System.out.print("+~~");
}
System.out.println("+~");
可以是这样的:
for (int i = 0; i < 16; i++){
System.out.print("~+~");
}
System.out.println();
更改之处:
更好的格式化
循环并打印
~+~
模式 System.out.print("+~");
for (int i = 1; i <= 15; i++){
System.out.print("++~");
}
System.out.println("+");
至:
for (int i = 0; i < 16; i++){
System.out.print("+~+");
}
System.out.println();
所做的更改:
>更好的格式化
循环并打印
+~+
模式所有修补程序都有一些共同点:
缩进和格式化
查找正确的模式
其他更改:
使用方法:
当前所有代码在
main
方法中。将其拆分。最终代码:
public class Exercises {
public static void main (String[] args){
printTildes();
printTPT_Pattern();
printPTP_Pattern();
printTildes();
}
private static void printTildes() {
for (int i = 0; i < 48; i++){
System.out.print("~");
}
System.out.println();
}
private static void printTPT_Pattern() {
for (int i = 0; i < 16; i++){
System.out.print("~+~");
}
System.out.println();
}
private static void printPTP_Pattern() {
for (int i = 0; i < 16; i++){
System.out.print("+~+");
}
System.out.println();
}
}
评论
\ $ \ begingroup \ $
“仅打印一个字符,以提高性能” —请停止鼓励微优化。建议这样的“改进”会使人们相信过早的优化是个好主意。在这种情况下,我认为与其余代码的一致性要重要得多。而且,实际上,至少在OpenJDK中,print(char)委托给print(String)而不是相反,因此,可忽略的性能提高是在另一个方向上。
\ $ \ endgroup \ $
– wchargin
15年11月26日在22:20
\ $ \ begingroup \ $
这种回答被接受了,但不满足任务要求。明确要求“写嵌套循环”以产生给定的输出,答案没有嵌套循环。 -1
\ $ \ endgroup \ $
–CiaPan
2015年11月27日7:34
\ $ \ begingroup \ $
这3种方法非常接近,可以重构为一种。
\ $ \ endgroup \ $
–叙利亚
15年11月27日在8:23
#2 楼
您并不是以最合乎逻辑的方式分解模式。每行仅包含三个字符的重复块。public class SquigglePlus {
private static final String[] PATTERNS = { "~~~", "~+~", "+~+", "~~~" };
public static void main(String[] args) {
for (int line = 0; line < PATTERNS.length; line++) {
for (int col = 0; col < 48; col += PATTERNS[line].length()) {
System.out.print(PATTERNS[line]);
}
System.out.println();
}
}
}
或者,内部循环可以数到16:
for (int i = 0; i < 16; i++) { … }
。请注意,在Java中,这是最常见的计数方式:从0开始,并使用<
进行终止检查。另一种方法(for (int i = 1; i <= 16; i++) { … }
)不会出错,但是通常只有在有特殊原因的情况下,才这样写。更好的方法是,使用现代的增强型for循环代替旧的-样式计数循环。
public class SquigglePlus {
private static final String[] PATTERNS = { "~~~", "~+~", "+~+", "~~~" };
public static void main(String[] args) {
for (String pattern : PATTERNS) {
for (int col = 0; col < 48; col += pattern.length()) {
System.out.print(pattern);
}
System.out.println();
}
}
}
评论
\ $ \ begingroup \ $
由于您显式地计算出打印出的字符,因此不需要保持等长的长度-您可以将每个字符缩至最短的时间:PATTERNS = {“〜”,“〜+〜”,“ +〜 +“,”〜“};
\ $ \ endgroup \ $
–CiaPan
15年11月27日在7:30
\ $ \ begingroup \ $
一种不太常用的方法是向下计数:for(int charstowrite = 48; charstowrite> 0; charstowrite-= pattern.length())这里似乎没有任何好处,但是如果您得到一些长度变量而不是48常数,它允许循环条件表达式将计数变量与常数0进行比较,而不是比较两个变量。
\ $ \ endgroup \ $
–CiaPan
15年11月27日在12:15
#3 楼
一般情况您有两个像这样的循环:
for (int i = 1; i <= 4; i++){
for (int j = 1; j <= 12; j++){
System.out.print("~");
}
}
这只是嵌套循环为了嵌套循环。我知道需求状态规定要使用嵌套循环,但是您不应仅出于此目的而故意使代码效率低下。这应该只是
for (int i = 1; i <= 48; i++)
您正在做很多事情。如果您使用类似
System.out.print()
之类的代码,并在其后附加字符,并且在完成后仅在末尾打印一次,则代码将更加清晰:方法
您所采用的方法并不理想,正如其他答案所解决的那样。对于如何解决这样的问题,我将采取一种全新的方法。因为它们永远不会改变。
行长(48)
行数(4)
每行都有自己的模式(模式本身不是很重要)
我们可以做一些基本的扶手椅数学运算,只需看一下线条就可以推断出一些东西。
48可被2、3、4整除8、12、16等。
如果要均匀地划分线段,则模式必定会成为其中的一种。模式是3。
所以,让我们在顶部声明所有这些:
class Exercises {
public static void main (String[] args){
StringBuilder output = new StringBuilder("");
for (int i = 1; i <= 48; i++){
output.append("~");
}
output.append("\n");
output.append("~");
//etc.
System.out.print(output);
}
}
}
所以我们知道每行多长时间,以及每个模式重复多少次,我们需要首先遍历每行,然后遍历每行字符。因此,骨架可能看起来像这样:
final int NUMBER_OF_LINES = 4;
final int LINE_LENGTH = 48;
final int PATTERN_LENGTH = 3;
final String[] LINE_NUMBER_PATTERNS = {"~~~","~+~","+~+","~~~"};
您还注意到我做了一个
StringBuilder
,它是一个字符串数组,每行包含一个模式。模式可以是任何字符串,任何长度。数组是按String[]
索引的,因此我们将使用0
至0
来计数行,而不是3
至1
。 (注意,请使用4
而不是<
,因为我们要在第四行的索引<=
处停止) for (int currentLine = 1; currentLine <= NUMBER_OF_LINES; currentLine++) {
for (int i = 1; i <= LINE_LENGTH; i += PATTERN_LENGTH) {
// do some stuff here
}
}
它输出此结果,这几乎是正确的:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ + ~~ + ~~ + ~~ + ~~ + ~~ + ~~ + ~~ + ~~~~ + ~~ + ~~ + ~~ + ~~ + ~~ + ~~ + ~~ +〜+〜++〜++〜++〜++〜++〜++〜++〜++〜++〜++〜++〜++〜++〜++ 〜++〜+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~
因此,我们所缺少的是在退出内部循环之后,在每行结尾处换行
3
。一切都说完了,这就是我们所拥有的,并且运行良好。 (ideone.com上的演示) for (int currentLine = 0; currentLine < NUMBER_OF_LINES; currentLine++) {
for (int i = 1; i <= LINE_LENGTH; i += PATTERN_LENGTH) {
output.append(LINE_NUMBER_PATTERNS[currentLine]);
}
}
评论
\ $ \ begingroup \ $
如何使用for(int currentLine = 0; currentLine
–西蒙·福斯伯格
15年11月26日在19:08
\ $ \ begingroup \ $
当您拥有LINE_NUMBER_PATTERNS.length时,为什么还要使用NUMBER_OF_LINES?
\ $ \ endgroup \ $
–西蒙·福斯伯格
15年11月26日在19:09
\ $ \ begingroup \ $
第一个很棒的答案。只有两个小巧的尼特。 (1)具有main函数的所有功能使维护或修改变得更加困难。返回stringbuilder的函数会更好。 (2)打印件是一个问题,因为它们将您要执行的操作与输出结果结合在一起。例如,第一和最后的图案/线是相同的,打印出中间结果使利用这一事实变得更加困难。
\ $ \ endgroup \ $
– jmoreno
15年11月28日在5:52
\ $ \ begingroup \ $
@jmoreno我完全同意,我希望你能理解,我以“初学者”的身份来尝试并匹配问题的精神,尽管我当然从中学到了:)
\ $ \ endgroup \ $
– ran
15年11月28日在7:47
\ $ \ begingroup \ $
@Phrancis:当然,我理解这一点,第二点是我的主要观点(因为轻微的挑剔可能会有一个“主要”观点),并且旨在解决您的“本质上没有错”。我认为混合计算值和输出结果有问题。我曾/将建议从“ While”中删除所有内容,然后删除“,”。
\ $ \ endgroup \ $
– jmoreno
15年11月28日在16:14
#4 楼
模式。它们不是很可爱吗?我的代码中有两件事我不喜欢:
您正在使用很多重复的
System.out.print
调用,确实有一些开销(可能被认为是过早的优化,但我认为对此有所了解)。您没有尽可能多地利用这些模式。
看一下您当前的代码:
System.out.print("~");
for (int i = 1; i <=15; i++){
System.out.print("+~~");
}
System.out.println("+~");
System.out.print("+~");
for (int i = 1; i <= 15; i++){
System.out.print("++~");
}
System.out.println("+");
您在这里做了一个非常有趣的拆分。如果看一下模式,您会发现第一个实际上只是
~+~
的一行,第二个实际上是+~+
。虽然您的要求可能是使用嵌套的for循环,但我不会认为这是最好的方法,也是一种教育活动,我将解释如何以一种我认为更好的方法进行操作。
我将创建一个返回
String
的方法public static String createPattern(String pattern, int length) {
if (pattern.isEmpty()) {
throw new IllegalArgumentException("Pattern cannot be empty");
}
StringBuilder builder = new StringBuilder(length);
while (builder.length() < length) {
int strLength = Math.min(pattern.length(), length - builder.length());
builder.append(pattern, 0, strLength);
}
return builder.toString();
}
然后可以使用此方法:
String cleanLine = createPattern("~~~", 48);
System.out.println(cleanLine);
System.out.println(createPattern("~+~", 48));
System.out.println(createPattern("+~+", 48));
System.out.println(cleanLine);
或,您可以继续将您的模式视为一系列“ + ~~”(已向右移动了一步),这可以通过使用
shift
方法来完成。public static String shift(String original, int stepsRight) {
if (Math.abs(stepsRight) >= original.length()) {
throw new IllegalArgumentException("Steps to shift, in either direction, must be less than string length");
}
if (stepsRight < 0) {
// shifting left one step is the same as shifting it right (length - 1) steps.
stepsRight += original.length();
}
int split = original.length() - stepsRight;
return original.substring(split) + original.substring(0, split);
}
那么您可以执行以下操作:
String cleanLine = createPattern("~~~", 48);
System.out.println(cleanLine);
System.out.println(createPattern(shift("+~~", 1), 48));
System.out.println(createPattern(shift("++~", -1), 48));
System.out.println(cleanLine);
虽然我会使用非转换模式版本,但是如果您想制作转换模式,则可能会有用具有相同模式但已移动的多行。
评论
\ $ \ begingroup \ $
从某种意义上讲,存在嵌套,但是它不是练习所要求的嵌套的for循环。
\ $ \ endgroup \ $
– 200_success
15年11月26日在18:44
\ $ \ begingroup \ $
@ 200_success嵌套,嗯。。。显然没有对此要求给予太多关注。虽然可能对需求有轻微的误解,但我发现嵌套的for循环并不是最好的选择。在我的答案中添加了对此的评论。
\ $ \ endgroup \ $
–西蒙·福斯伯格
15年11月26日在19:00
#5 楼
要生成更好的代码,需要做的就是学习识别代码中的模式,以查看是否要复制功能和代码。因此,当我查看您的代码时,我做的第一件事是问自己,某处是否存在重复项?答案是肯定的!for (int i = 1; i <= 4; i++){
for (int j = 1; j <= 12; j++){
System.out.print("~");
}
}
这段代码既位于方法的开头,也位于方法的结尾。因此,您可以自己提取一种方法,而不必重复此方法!
其余的代码是“正确的”,因为它没有重复但仍然没有解决问题的好方法。任务是尝试考虑必须中断的模式。您应该已经看到第二行是序列
~+~
的副本,第三行是+~+
的重复。我建议您考虑使用此解决方案来输出。 #6 楼
这是基于Java 8Stream
的方法... :) 使用@ 200_success的答案作为基础,我们知道重复的组可以只是
"~~~", "~+~", "+~+", "~~~"
(或跟随@CiaPan的评论,仅"~"
,因为我们通过比较长度来“循环”)。我们也知道我们需要重复48 / length of each String
次。private static final int LENGTH = 48;
// Usage
// Original
// Stream.of("~~~", "~+~", "+~+", "~~~")
Stream.of("~", "~+~", "+~+", "~")
.map(v -> String.join("", Collections.nCopies(LENGTH / v.length(), v)))
.forEach(System.out::println);
构造所需
Stream
元素的String
。对于每个元素,
map()
通过join()
-使用List
创建的每个元素的nCopies()
,将它们获得所需的结果。这使我们能够轻松地为给定数量的副本LENGTH / v.length()
创建重复元素。最后,将
forEach()
个元素传递给System.out.println(String)
(在此处用作方法参考)。当然,您可以简单地用硬编码的
LENGTH / v.length()
代替16
(如果我们也使用"~~~"
),但是我觉得这对于将来的变化有更大的灵活性(只需要注意舍弃LENGTH
的非因数)。 br /> edit:将其转换为显式的
for
-loop结构,以更好地满足您的任务要求相对简单:// Original
// for (String element : Arrays.asList("~~~", "~+~", "+~+", "~~~")) {
for (String element : Arrays.asList("~", "~+~", "+~+", "~")) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < LENGTH / element.length(); i++) {
builder.append(element);
}
System.out.println(builder.toString());
}
类似的步骤正在执行以下操作:我们遍历相同的元素,通过使用
StringBuilder
为所需的副本数重复连接一个元素来“映射”每个元素,最后,我们打印每个toString()
的StringBuilder
表示形式。 >#7 楼
没有人真正回答过的这个问题的关键部分是;编写嵌套的forloops
我的第一个想法是只是为了保持简单;
public class Exercises
{
public static void main (String[] args)
{
for (int row = 0; row < 4; row++)
{
// Loop 0 - 15.
// "column" 0 - "column" 15 are each 3 chars wide, for a total of 48 chars.
for (int column = 0; column < 16; column++)
{
switch (row)
{
// First and last row are the same, don't repeat code!
case 0:
case 3:
System.out.print("~~~");
break;
case 1:
System.out.print("~+~");
break;
case 2:
System.out.print("+~+");
break;
}
}
// There's a newline at the end of each row, print it here, once the "column" printing is done.
System.out.print("\n");
}
}
}
我不会说这太棒了,但它涵盖了您的老师/导师/自助指南正在尝试的要点make。
我们正在使用嵌套循环。这是关键。
我们正在使用正确命名的变量
row
和column
。 还有其他事情可以做;
整个代码可以从
main
中取出。并采用自己的方法; WritePattern()
。这使代码更具可扩展性。再说下一课,重复上述模式,您所要做的就是在方法中添加一个参数,并将该参数乘以4。每个case语句也可以使用单独的方法,例如
WriteRowPattern(int columnLimit, string pattern)
其中47 / 16替换为columnLimit参数。同样,这使它更具可扩展性。进行此更改后,我们将从固定模式转换为所需的任何模式。评论
\ $ \ begingroup \ $
我认为我们对“简单”有不同的定义吗?
\ $ \ endgroup \ $
– h.j.k.
15年11月27日在1:27
\ $ \ begingroup \ $
同意。我认为我不会教有关匿名函数,映射和“ foreach”循环声明的初学者。尤其是因为此问题的焦点嵌套在循环中。我认为很容易理解第一行是每一行,第二行是每一列。您可能可以调整switch语句并使它更清晰一些,仅此而已。如果您不了解特定的部分,很乐意进一步解释。
\ $ \ endgroup \ $
–特伦特
2015年11月27日5:29
\ $ \ begingroup \ $
嗯,您的解决方案的第一行和最后一行都缺少一个字符,因为您将\ n打印为第48个字符,而实际上应该是第49个字符。而且,显式地跳过第二行和第三行的列值17 ... 47的输出是...古怪的。恕我直言,不得不使用0 ... 4来遍历每一行,然后依靠开关来确定应该在每行打印什么,这也有点麻烦。在必须两次指定“ ~~~”与引入索引+开关之间,我认为前者既简短又易于实现。
\ $ \ endgroup \ $
– h.j.k.
15年11月27日在5:49
\ $ \ begingroup \ $
是的,好的,我没有Java编译器来检查输出,这很愚蠢,但我的工作很简单。回想一下您第一次学习Java的时间。在内部for循环中引用外部for循环的变量是您首先要教的一件事,我很确定这是OP的老师/辅导员/自助书所试图尝试的概念。
\ $ \ endgroup \ $
–特伦特
15年11月27日在6:07
\ $ \ begingroup \ $
@ h.j.k。是的,我可能会拉出换行符,然后将其放在内部for循环的末尾/外部,即,在每行写完“列”之后隐式地写一个换行符。我要的是快速/简单,而不是微观的优化/重构。
\ $ \ endgroup \ $
–特伦特
15年11月27日在6:36
#8 楼
我更喜欢其他答案,但是如果您真的被迫使用嵌套循环,我会去: for (int line = 0; line < 4; line++) {
for (int i = 0; i < 16; i++) {
int type = line % 3;
if (type == 2) {
System.err.print("+~+");
} else if (type == 1) {
System.err.print("~+~");
} else {
System.err.print("~~~");
}
}
System.err.println();
}
或者如果您认为三元运算符足够可读: >
for (int line = 0; line < 4; line++) {
for (int i = 0; i < 16; i++) {
int remainder = line % 3;
System.err.print(remainder == 2 ? "+" : "~");
System.err.print(remainder == 1 ? "+" : "~");
System.err.print(remainder == 2 ? "+" : "~");
}
System.err.println();
}
评论
您的缩进真的很奇怪。