Query expression and loop control

Source: Internet
Author: User

For, do... While, while, foreach are commonly used loop control statements in most programming languages, and Query expressions in C # can achieve the same effect.

The query expression makes the programming style more declarative from the "imperative ". The query expression defines the desired result and the method that needs to be executed to achieve the result, rather than how to implement it. Here, the focus is on the query expression. Through the extension method, the query expression can better express the intention than the imperative loop structure.

The following statement shows filling an array in the imperative style and printing it to the console:

int[] foo = new int[100];for (int num = 0; num < foo.Length; num++){   foo[num] = num * num;}foreach (int i in foo){   Console.WriteLine(i.ToString());}  

Even if you implement such a small function, you still pay attention to how to implement it instead of how to implement it. changing this code to a query expression makes the code easier to read and use:

int[] foo = (from n in Enumerable.Range(0, 100) select n * n).ToArray();

The second loop can be rewritten as follows using the extension method:

foo.ForAll(n => Console.WriteLine(n));

Or more concise:


In. Net BCl, The foreach extension method has the implementation method for list <t>. We can add a forall Extension Method for ienumerable <t> to implement it as follows:

public static class Extensions{    public static void ForAll<T>(this IEnumerable<T> sequence, Action<T> action)    {        foreach (T item in sequence)        {            action(item);        }    }}

It may seem inconspicuous, but it is just an extension method, but this can make the code more reusable. forall can be used to execute operations on a sequence element at any time.

The above problem may seem simple, not enough to see the benefits of using the query syntax. Here is a more complex one.

Many operations require nested loop operations. If a (x, y) pair from 0 to 99 needs to be generated, the common practice is:

public static IEnumerable<Tuple<Int32, Int32>> ProduceIndices(){   for (int x = 0; x < 100; x++)   {      for (int y = 0; y < 100; y++)      {          yield return Tuple.Create(x, y);      }   }}

Or change to the query expression:

public static IEnumerable<Tuple<Int32, Int32>> ProduceIndices(){    return from x in Enumerable.Range(1, 100)           from y in Enumerable.Range(1, 100)           select Tuple.Create(x, y);}

The two look similar, but with the complexity of the problem, the query expression can still be concise. Now let's change the problem to: only generate a point with the sum of X and Y less than 100, and compare the implementation of the two:

public static IEnumerable<Tuple<Int32, Int32>> ProduceIndices2(){    for (int x = 0; x < 100; x++)    {        for (int y = 0; y < 100; y++)        {            if (x+y<100)                yield return Tuple.Create(x, y);        }    }}public static IEnumerable<Tuple<Int32, Int32>> ProduceIndices2(){    return from x in Enumerable.Range(1, 100)           from y in Enumerable.Range(1, 100)           where x+y<100           select Tuple.Create(x, y);}


The gap is still not obvious, but imperative statements start to hide what we want. Then the problem becomes more complicated. Now, we need to sort the returned points in descending order of distance from the origin point.

public static IEnumerable<Tuple<Int32, Int32>> ProduceIndices3(){    var storage = new List<Tuple<int, int>>();    for (int x = 0; x < 100; x++)    {        for (int y = 0; y < 100; y++)        {            if (x+y<100)            storage.Add(Tuple.Create(x, y));        }    }    storage.Sort((point1,point2)=>                (point2.Item1*point2.Item1+point2.Item2*point2.Item2).CompareTo                (point1.Item1 * point1.Item1 + point1.Item2 * point1.Item2)                );    return storage;}public static IEnumerable<Tuple<Int32, Int32>> ProduceIndices3(){    return from x in Enumerable.Range(1, 100)           from y in Enumerable.Range(1, 100)           where x + y < 100           orderby (x * x + y * y) descending           select Tuple.Create(x, y);}

Now, the gap is beginning to emerge, and the code in the imperative style is hard to understand. If you do not really look at it, it is difficult to suddenly understand what is returned by a bunch of things behind the function. Without comments, this imperative code is hard to understand. The imperative Code emphasizes the Code Execution Process too much, and it is easy to get rid of what we originally wanted in this complicated process.

A better query expression than a loop control structure is: a query expression can be better combined to organize algorithms in a small, streamlined segment to execute a series of operations. The query's inert execution model allows developers to perform a series of operations in a loop class. The query expression cannot do this. You must store the results of each loop, and then construct a new loop operation to execute the last operation result.

The last example demonstrates how to work. The operations combine filtering (where clause), sorting (orderby clause), and projection (select statement). All these operations are completed in a traversal operation. In the command-type version, you need to create a zero-Time Storage object, and then perform column operations on the object separately.

Each query expression has a corresponding method call expression. Sometimes, the query expression is more natural, and sometimes the method call is more natural. Obviously, in the above example, the query expression version is easier to read. The following is the version of the method call:

public static IEnumerable<Tuple<Int32, Int32>> ProduceIndices3(){    return Enumerable.Range(1, 100).            SelectMany(x => Enumerable.Range(1, 100),            (x, y) => Tuple.Create(x, y)).Where(pt => pt.Item1 + pt.Item2 < 100).            OrderByDescending(pt => pt.Item1 * pt.Item1 + pt.Item2 * pt.Item2);}

In this example, the query expression may be easier to read than the method expression, but other examples may be different. Some method expressions do not have corresponding Query expressions. Some methods, such as take, takewhile, Skip, skipwhile, Min, and Max, must use method expressions in some cases.

Some may query the slow execution speed of expressions than loop execution, depending on the specific situation. Sometimes clear code may be more important than speed. Before Improving the program algorithm, you can consider the parallel extension library Plinq of LINQ. You can use. asparallel () to perform query operations in parallel.

C # Is a imperative programming language. You can use the most familiar method to write code. However, these traditional methods may not be the best. When you find that you need to use a loop structure to execute an operation, try to rewrite it to a query expression. If the query expression does not work, try a method expression. In most cases, you will find that using a query expression or Method Expression makes the code more concise and clear than using a traditional cyclic imperative structure.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.