7 tricks to simplify your programs with LINQ

7 tricks to simplify your programs with LINQ

Ever since I learned about LINQ, I keep discovering new ways to use it to improve my code. Every trick makes my code a little bit faster to write, and a little bit easier to read.

This posting summarizes some of the tricks that I came across. I will show you how to use LINQ to:

If you have your own bag of LINQ tricks, please share them in the comments! Also, if you like this article, you may like my next article, Extended LINQ: additional operators for LINQ to objects.

1. Initialize an array 

Often, you need to initialize elements of an array to either the same value, or to an increasing sequence values, or possibly to a sequence increasing or decreasing by a step different from one. With LINQ, you can do all of this within the array initializer – no for loops necessary!

In the following code sample, the first line initializes a to an array of length 10 with all elements set to -1, the second line initializes b to (0,1,..9), and the third line initializes c to (100,110,…,190):

int[] a = Enumerable.Repeat(-1, 10).ToArray();
int[] b = Enumerable.Range(0, 10).ToArray();
int[] c = Enumerable.Range(0, 10).Select(i => 100 + 10 * i).ToArray();

A word of caution: if you are initializing large arrays, you may want to forego the elegance and use the old-fashioned for loop instead. The LINQ solution will grow the array dynamically, so garbage arrays will need to be collected by the runtime. That said, I use this trick all the time when initializing small arrays, or in testing/debugging code.

2. Iterate over multiple arrays in a single loop 

A friend asked me a C# question: is there a way to iterate over multiple collections with the same loop? His code looked something like this:

foreach (var x in array1) {
    DoSomething(x);
}

foreach (var x in array2) {
    DoSomething(x);
}

In his case, the loop body was larger, and he did not like the duplicated code. But, he also did not want to allocate a new array to hold elements from both array1 and array2.

LINQ provides an elegant solution to this problem: the Concat operator. You can rewrite the above two loops with a single loop as follows:

foreach (var x in array1.Concat(array2)) {
    DoSomething(x);
}

Note that since LINQ operates at the enumerator level, it will not allocate a new array to hold elements of array1 and array2. So, on top of being rather elegant, this solution is also space-efficient.

3. Generate a random sequence 

This is a simple trick to generate a random sequence of length N:

Random rand = new Random();
var randomSeq = Enumerable.Repeat(0, N).Select(i => rand.Next());

Thanks to the lazy nature of LINQ, the sequence is not pre-computed and stored in an array, but instead random numbers are generated on-demand, as you iterate over randomSeq.

4. Generate a string 

LINQ is also a nice tool to generate various kinds of strings. I found this quite useful to generate strings for testing and debugging purposes.

Let’s say that you want to generate a string with the repeating pattern "ABCABCABC…" of length N. Using LINQ, the solution is quite elegant:

string str = new string(
    Enumerable.Range(0, N)
    .Select(i => (char)('A' + i % 3))
    .ToArray());

[EDIT] Petar Petrov suggested another interesting way to generate strings with LINQ. His approach applies to different scenarios than my solution above:

string values = string.Join(string.Empty, Enumerable.Repeat(pattern, N).ToArray());

5. Convert sequences or collections 

One thing you cannot do in C# or VB is to cast a sequence of type T to a sequence of type U, even if T us a derived class from U. So, you cannot just simply cast List<string> to List<object>. (For an explanation why, see Bick Byers’ posting).

But, if you are trying to convert IEnumerable<T> to IEnumerable<U>, LINQ has a simple and efficient solution for you:

IEnumerable<string> strEnumerable = ...;
IEnumerable<object> objEnumerable = strEnumerable.Cast<object>();

If you need to convert List<T> to List<U>, there is also a simple LINQ solution, but it involves copying the list:

List<string> strList = ...;
List<object> objList = new List<object>(strList.Cast<object>());

[EDIT] Chris Cavanagh suggested an alternate solution:

var objList = strList.Cast<object>().ToList();

6. Convert a value to a sequence of length 1 

When you need to convert a single value to a sequence of length 1, what do you do? You could construct an array of length 1, but I prefer the LINQ Repeat operator:

IEnumerable<int> seq = Enumerable.Repeat(myValue, 1);

7. Iterate over all subsets of a sequence 

Sometimes it is useful to iterate over all subsets of an array. This situation arises quite frequently in brute-force solutions to hard problems. For small inputs, subset sum, boolean satisfiability and the knapsack problem can all be solved easily by iterating over all subsets of some sequence.

In LINQ, we can generate all subsets of array arr as follows:

T[] arr = ...;
var subsets = from m in Enumerable.Range(0, 1 << arr.Length)
              select
                  from i in Enumerable.Range(0, arr.Length)
                  where (m & (1 << i)) != 0
                  select arr[i];

Note that if the number of subsets overflows an int, the above code will not work. So, only use it if you know that the length of arr is at most 30. If the length of arr is greater than 30, chances are that you don’t want to iterate over all of its subsets anyway because it is going to take minutes or more.

Comments and Conclusion

I hope you find these tricks useful and applicable to your programs.

The code samples in this posting are all implemented in C#, but they can be easily adapted to just about any other .Net language. However, LINQ is most conveniently used from .Net languages that support extension methods, lambda expressions and type inference, such as C# and Visual Basic.

To the best of my knowledge, each code sample in this posting works, but – as is common on the web – I don’t make any guarantees. As always, double check any code before using it.

Related:

此条目发表在未分类分类目录,贴了, 标签。将固定链接加入收藏夹。