回归基础:if,for和switch之外的事情
[原文发表地址] Back to Basics: Moving beyond for, if and switch
[原文发表时间] 2012-04-26 19:59
我访问了很多的客户,查看了大量的代码。我还在我以前的工作中接触到了很多大型产品代码基地,我看到了大量的 if、 for和switch语句。我看到循环之中还嵌套着循环,其中if做着各种数据转换,从一种格式转换为另一种。我看到解析字符串来获取数据,用英文来表达这个意思很简单,但如果是编写代码的话,就需要100 行。
当我们刚起步编程时,我们就首先学习if,接着是for,然后是滥用 switch 语句。
几个星期前我在Miguel的博客上看到这片小小的代码段:
1: var biggerThan10 = new List;
2: for (int i = 0; i < array.Length; i++){
3: if (array [i] > 10)
4: biggerThan10.Add (array[i]);
5: }
它很简单。排列一组整数数组,然后将那些比 10 大的数字做一个新的列表。我们已经百万次看到类似这样的代码。这里是其他几种语言所编写的同一事情。
C#
1: var a = from x in array where x > 10 select x;
2: var b = array.Where(x => x > 10);
Ruby
1: a = array.select{|x| x >10}
JavaScript
1: a = array.filter(function(x){return x > 10});
比起上述的循环和if,我更喜欢编写这些一行操作的代码。我在世界上看到了很多,所以或许人们没有看见足够多的例子。我要求请求 Twitter 上的朋友提交他们的例子。谢谢你们,Twitter 朋友们 !
这里有几个很好的例子。Iron Shay在他的博客中有一些不错的 LINQ示例。请在评论中分享你的例子。 请务必使用 <pre> 标记。
说明: 这是关于"将事情简化为一行",同样的解决方案,同等的可读性,它们比循环更简单、 简洁和少出错。
1: def calculate_primes(n):
2: no_primes = []
3: primes = []
4: for i in range(2, 8):
5: for j in range(i*2, n, i):
6: no_primes.append(j)
7: for x in range(2, n):
8: if x not in no_primes:
9: primes.append(x)
10: return primes
11:
12: calculate_primes(500)
13: # Can be like this instead!
14: (lambda n: [x for x in range(2, n) if x not in [j for i in range(2, 8) for j in range(i*2, n, i)]])(500)
1: foreach (var i in categories) {
2: foreach (var x in GetAllChildCategories(i.Id)) {
3: yield return x;
4: }
5: }
6:
7: //Can be... return categories.SelectMany(i => this.GetAllChildCategoriesIds(i.Id));
1: var inputNumbersInString = Console.ReadLine();
2: var inputNumbersStringArray = inputNumbersInString.Split(' ');
3: var inputNumbers = new List<int>();
4:
5: for (int i = 0; i < inputNumbersStringArray.Length; ++i) {
6: inputNumbers.Add(int.Parse(inputNumbersStringArray[i]));
7: }
8:
9: int maxNumber = inputNumbers[0];
10:
11: for (int i = 1; i < inputNumbers.Count; ++i)
12: if (inputNumbers[i] > maxNumber)
13: maxNumber = inputNumbers[i];
14:
15: Console.WriteLine(maxNumber);
16:
17: //Or rather...
18:
19: Console.WriteLine(Console.ReadLine().Split(' ').Select(t => int.Parse(t)).ToList().Max());
1: // create a poker deck as a list of two characters strings:
2: // rank, suite
3:
4: char[] figures = "23456789TJQKA".ToCharArray();
5: char[] suites = "SHDC".ToCharArray();
6: List<string> deck = new List<string>();
7:
8: foreach (var figure in figures) {
9: foreach (var suite in suites) {
10: deck.Add(string.Format("{0}{1}", figure, suite));
11: }
12:
13: }
14: //Or, neatly
15: var cards = from r in "23456789TJQKA" from s in "SHDC" select "" + r + s;
1: bool include = false;
2: if (op == Operator.And) {
3: bool current = true;
4: foreach (var item in Items) {
5: current = current & item.Process();
6: }
7: include = current;
8: }
9: else {
10: bool current = false;
11: foreach (var item in Items) {
12: current = current | item.Process();
13: }
14: include = current;
15: }
16: return include;
17:
18: //Or this lovely Aggregate
19:
20: return op == Operator.And ?
21: Items.Aggregate(true, (current, item) => current & item.Process()) :
22: Items.Aggregate(false, (current, item) => current | item.Process());
1: sbyte[] sByteArray = new sbyte[100];
2: byte[] uByteArray = new byte[sByteArray.Length];
3:
4: for (int i = 0; i < sByteArray.Length; i++) {
5: uByteArray[i] = (byte)sByteArray[i];
6: }
7:
8: //Or, instead of the loop above
9: byte[] uByteArray1 = Array.ConvertAll(sByteArray, x => (byte)x);
Scott:在这里我不得说我更喜欢第一个选项。;)
1: // This is the "classic" solution to the FizzBuzz problem.
3: if (i % 3 == 0 && i % 5 == 0) {
4: Console.WriteLine("FizzBuzz");
2: for (int i = 1; i <= 100; i++) {
5: }
6: else if (i % 3 == 0) {
7: Console.WriteLine("Fizz");
8: }
9: else if (i % 5 == 0) {
10: Console.WriteLine("Buzz");
11: }
12: else {
13: Console.WriteLine(i.ToString());
14: }
15: }
16:
17: // One line
18: Enumerable.Range(1, 100).ToList().ForEach(n => Console.WriteLine((n % 3 == 0) ? (n % 5 == 0) ? "FizzBuzz":"Fizz" : (n % 5 == 0) ? "Buzz" : n.ToString()));
一个好的代码段实现手段 ...我感到惊讶的是更多的人不使用此。
1: var temp = String.Empty;
2: foreach (var entry in myStringList) {
3: if (String.IsNullOrEmpty(temp)) {
4: temp = entry;
5: }
6: else {
7: entry += ", " + entry;
8: }
9: }
10:
11: //becomes
12:
13: var temp = String.Join(", ", myStringList)
用一行F#编写的带有属性的一个类。这将要用十行甚至更多行的C#代码来编写。
1: type Person = { Name:string; Age:int }
1: /// Input is a string with numbers : 10+20+30+40
2: /// Output is integer with required sum (100)
3: string input = "10+20+30+40";
4: var result = Regex.Split(input, @"\D+").Select(t => int.Parse(t)).Sum();
5: Console.WriteLine("Result is {0}" ,result);
对于程序人员来说,除了我们所学的前三个关键字,还有很多东西可用于编程。您最喜欢的能帮助你摆脱基础知识,移到下一个级别的模式是什么 (不管是什么语言)?