回归基础: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)

来自Aaron Bassett

   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));

来自James Hull

   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());

来自Amit Saraswat

   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;

来自Jack Nova

   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()); 

来自Kevin Meiresonne

   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);

来自Fahad Mustafa

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()));

来自Rudi Larno

一个好的代码段实现手段 ...我感到惊讶的是更多的人不使用此。

   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)

来自Holger Adam

用一行F#编写的带有属性的一个类。这将要用十行甚至更多行的C#代码来编写。

   1: type Person = { Name:string; Age:int }

来自Phillip Trelford

   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);

来自Srinivas Iyengar

对于程序人员来说,除了我们所学的前三个关键字,还有很多东西可用于编程。您最喜欢的能帮助你摆脱基础知识,移到下一个级别的模式是什么 (不管是什么语言)?

 


Comments (0)

Skip to main content