如何编写代码解决问题,新手指南.(译文)
By S.F.
本文链接 https://www.kyfws.com/news/how-to-write-code-to-solve-a-problem-a-beginners-g/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 8 分钟阅读 - 3839 个词 阅读量 0如何编写代码解决问题,新手指南.(译文)
原文地址:https://www.codeproject.com/Articles/5282084/How-to-write-code-to-solve-a-problem-a-beginners-g
原文作者:OriginalGriff
译文由本站翻译
前言
First steps in development: break it, break it again! 开发的第一步:打破它,再打破它! By the time you’ve read this, you will be an UberKoderz, just like me! No. No, you won’t. But … you will have one of the really important tools available to you to start writing code: “Breaking it into smaller bits”. And no, I’m not an UberKoderz either. 到您读完本文时,就像我一样,您将成为UberKoderz!不,你不会.但是…您将拥有真正重要的工具之一,可以用来开始编写代码:“将其分解为较小的部分”.不,我也不是UberKoderz.
Introduction(介绍)
All the code here is in C# - buit it’s all pretty simple stuff, and the process is the same in any language. Just “bleep” over the brackets and semicolons if you don’t understand them!
这里的所有代码都在C#中-但这都是非常简单的东西,任何语言的处理过程都是相同的.如果您不了解括号和分号,只需"弄皱"它们!
Recently there was a question which involved a chunk of homework: write a method that reads a file and returns all the lines which are followed by a line containing three asterisks. And the code was terrible, even for a beginner - so bad I won’t embarass anyone by linking to it.
最近出现了一个涉及大量作业的问题:编写一种方法来读取文件并返回所有行,然后再返回包含三个星号的行.即使对于初学者来说,代码也很糟糕-太糟糕了,我不会通过链接到它而使任何人尴尬.
public static string FindLineAboveAsterisks(TextReader reader)
{
StringBuilder sbBuilder = new StringBuilder();
string result = reader.ReadLine();
string line = String.Empty;
while (result is object && (line = reader.ReadLine()) is object)
{
int startIndex = 21;
int length = 9;
if (line.Contains("***"))
{
sbBuilder.AppendLine(result);
return result;
}
{
result = line.Substring(startIndex, length);
}
}
return string.Empty;
You look at that code and you just start to wonder … Why? What is that indentation? What is that there for? Why do this? How you do expect that to work?
您查看该代码后,就开始怀疑…为什么?那是什么缩进?那有什么用为什么这样您希望它如何运作?
And of course, it doesn’t. It can’t work - and the reason why is the author just threw it together without thinking about the task at all.
当然,事实并非如此.它是行不通的-作者之所以把它放到一起而根本不考虑任务的原因.
My answer (expanded a little)(我的回答(扩大了一点))
That looks like it was thrown together without any thought about what you are trying to do!
看起来好像是在没有考虑您要做什么的情况下将其放在一起!
Blunt, I know. But I wanted to get his attention.(钝,我知道.但是我想引起他的注意.)
Throw it away, and think about your task: Read a file, find all the lines which are above lines with an asterisk, and return them.
扔掉它,然后考虑您的任务:读取文件,找到所有带有星号的行,然后将其返回.
Still blunt, but let’s think about it.(仍然直率,但让我们考虑一下.)
So let’s take it from the top: You need to return more than one line - so the obvious thing to do is to return a collection of strings instead of a single string. Because although you can return them as a single string, it makes life a lot harder for the code that calls your method - it has to “break it back up again” in order to use the information. Let’s change that:
因此,让我们从顶部开始:您需要返回多行-因此,显而易见的事情是返回字符串的集合而不是单个字符串.因为尽管您可以将它们作为单个字符串返回,但对于调用您的方法的代码而言,它的工作变得更加艰辛-为了使用信息,它必须"再次将其分解". 让我们更改一下:
public static List<string> FindLineAboveAsterisks(TextReader reader)
Now, it returns a collection of strings so the outside world can work with it.
现在,它返回一个字符串集合,以便外界可以使用它.
Think about what you are trying to get the method to do: don’t complicate things for the calling code - because you are going to call it one or more times, and you will write it once. If you make the outside world work harder then you are just adding work you have to do every time you use the method.(考虑一下您要尝试执行的方法:不要使调用代码复杂化-因为您将调用它一次或多次,并且将编写一次.如果您使外界的工作更加努力,那么您只是在每次使用该方法时都要做的工作.)
So if you need a collection of items, return a collection - don’t bodge round so that the outside world has to do more processing each time it calls you!(因此,如果您需要物品的收藏,请退还一个收藏-不要陷入困境,以免外界每次调用您时都要做更多的处理!)
But … why are you passing it a TextReader? That means each time you call it, the outside world has to do the work of creating, opening, passing, and closing the reader - which is silly. Pass the path instead, and let the method do what it wants with it:
但是…为什么要传递给它一个TextReader?这意味着每次您调用它时,外部世界都必须完成创建,打开,传递和关闭阅读器的工作-这很愚蠢.改为传递路径,然后让该方法使用它来做它想要做的事情:
public static List<string> FindLineAboveAsterisks(string filePath)
Now, the caller looks easier to work with.
现在,呼叫者看起来更容易使用.
Again, make life easier for yourself: you want to read a file? Pass the path and let the method decide what to do with it. If you pass a TextReader, or a Stream, then you are limiting what the outside world can do, and forcing a “shape” on code that may not be the easiest or most efficient for the job it has to do.(同样,让自己的生活更轻松:您想读取文件吗?传递路径并让方法决定如何处理.如果传递TextReader或Stream,则将限制外部世界可以执行的操作,并在代码上强加"形状",这对于执行其工作可能不是最容易或最有效的.)
The more “generic” you make parameters, then more flexible your code can be - and that means it can be reused - which saves you writing another, similar method to do much the same thing.(您设置的参数越"通用",代码就可以变得更加灵活-这意味着它可以被重用-从而节省了您编写另一个相似的方法来执行相同操作的时间.)
Let’s start filling in the method: We need a
List
to return, and to process every line in a file. If we want to use every line, then let’s just get them all and let the system handle it! That’s pretty easy:
让我们开始填写该方法:我们需要一个"列表"来返回并处理文件中的每一行.如果我们想使用每一行,那么让我们把它们全部拿来让系统处理吧!那很简单:
public static List<string> FindLineAboveAsterisks(string filePath)
{
List<string> lines = new List<string>();
foreach (string line in File.ReadLines(filePath))
{
// ...
}
return lines;
}
What could be simpler? We know there are two things we must do: return a collection of lines, and process all the lines in a file. So create the collection at the top of the method; return it at the end. Add a simple loop to give us each line at a time. Result: the code is simple, and easy to write. And if it’s easy to write, it’s probably going to work …(有什么可能更简单?我们知道必须做两件事:返回行集合,并处理文件中的所有行.因此,在方法顶部创建集合;最后返回.添加一个简单的循环,一次给我们每一行.结果:代码简单,易于编写.而且如果写起来很容易,它可能会起作用…)
Now, what do we have to do with the lines? Simple; we need to collect all the lines where the next line contains three asterisks. So we need to know what the last line was.
现在,我们与线路有什么关系? 简单;我们需要收集下一行包含三个星号的所有行. 所以我们需要知道最后一行是什么.
Think about it for a moment: inside the loop, how can we tell what the next line contains? Practically speaking we can’t (unless we compicate the code and use a different looping construct, but that’s messy). What we do know though is what the previous line was - because we have already processed it and can keep a copy for next time.(想一想:在循环中,我们如何分辨下一行包含的内容?实际上,我们不能这样做(除非我们使代码复杂化并使用不同的循环结构,但这很麻烦).我们所知道的只是上一行的内容-因为我们已经对其进行了处理,并且可以保留下一次副本.)
So turn the problem on it’s head and think of it as “find all the lines which contain three asterisks, and return the previous line for each”. A moments thinking tells you that gives the same result, and means we can work with “historical data” which we have allready looked at instead of “future data” that we haven’t.(因此,从头开始考虑问题,并将其视为"找到包含三个星号的所有行,并为每个行返回上一行".片刻的思考告诉您得出相同的结果,这意味着我们可以使用已经准备好的"历史数据"来代替尚未使用的"未来数据".)
Let’s add that:
让我们补充一点:
public static List<string> FindLineAboveAsterisks(string filePath)
{
List<string> lines = new List<string>();
string lastLine = "";
foreach (string line in File.ReadLines(filePath))
{
// ...
lastLine = line;
}
return lines;
}
Each time, we are adding a tiny amount of simple code - nothing complicated, so there is less to go wrong.(每次,我们都添加少量的简单代码-没什么复杂的,所以出错的地方更少了.)
We need to check
if
the current line contains “*”. If it does, add the last one to the collection. That’s easy too - a quickif
test will do it:
我们需要检查ʻif`当前行是否包含" ***".如果是这样,请将最后一个添加到集合中.这也很容易-一个快速的if测试可以做到:
public static List<string> FindLineAboveAsterisks(string filePath)
{
List<string> lines = new List<string>();
string lastLine = "";
foreach (string line in File.ReadLines(filePath))
{
if (line.Contains("***"))
{
lines.Add(lastLine);
}
lastLine = line;
}
return lines;
}
Hang on … it’s finished, isn’t it?
等一下…完成了,不是吗?
All we have to do now is call it and test it:
我们现在要做的就是调用它并进行测试:
string path = @"D:\Test Data\List of hats.txt";
foreach (string line in FindLineAboveAsterisks(path))
{
Console.WriteLine(line);
}
I could have shown you the original code for that … but you might have just finished eating …(我可以向您显示原始代码^但您可能刚吃完饭^)
Oh look - it works!
哦,看-有效!
So what did we do?(那我们做了什么?)
Basically, all we did was take a whole task and break it into littler ones:
基本上,我们所做的只是完成一项完整的任务并将其分解为更小的任务:
None of those tasks are difficult: they are a line or two of code and it’s pretty simple code as well.
这些任务都不是难事:它们是一两行代码,它也是非常简单的代码.
And that’s the secret: big tasks are made up of smaller ones, and those are made of even smaller ones.
这就是秘密:大任务由较小的任务组成,而任务甚至由较小的任务组成.
*You are used to that: you use it every day! *
您已经习惯了:每天都在使用它!
Task: “Have breakfast”
任务:“吃早餐”
Smaller tasks:
较小的任务:
Each of those tasks may be quite complicated:
这些任务中的每一个可能都非常复杂:
Subtask: “Go to kitchen”
子任务:“去厨房”
Those may have sub-sub-sub tasks:
这些可能具有子-子-子任务:
Sub-sub-task: “Work out where you are”
子子任务:“锻炼自己的位置”
Summary(概要)
The point is that every task can be broken down into smaller peices until you reach a task you either can do, or know how to find out how to do. If you wake up in a strange room, then you need to check for other people, and maybe ask them where the kitchen is - and so on.
关键是可以将每个任务分解成较小的部分,直到完成可以执行的任务或知道如何执行操作为止.如果您在陌生的房间里醒来,则需要检查其他人,并可能问他们厨房在哪里-依此类推.
Software tasks are the same; refine the task into smaller bits and some - probably all - can be done easily, and build up to completing bigger, more complex tasks that sound impossible.
软件任务是相同的;将任务细化为较小的部分,某些-可能全部-可以轻松完成,并逐步完成听起来更不可能的更大,更复杂的任务.
Just start by thinking instead of jumping into code: five minutes planning can save you hours of work!
只是从思考开始而不是跳入代码:五分钟的计划可以节省您的工作时间!
History(历史)
2020-10-06 Original Version
2020-10-06原始版本
2020-10-06 Typos. Always typos …
2020-10-06错字.总是错别字…
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
Dev Beginner 新闻 翻译