7 LINQ Tricks to Simplify Your Programs
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:
- Initialize an array
- Iterate over multiple arrays in a single loop
- Generate a random sequence
- Generate a string
- Convert sequences or collections
- Convert a value to a sequence of length 1
- Iterate over all subsets of a sequence
If you have your own bag of LINQ tricks, please share them in the comments!
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.
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.
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 = 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.
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.

Title…
Very interesting post. I would like to link back to it….
Title…
Very interesting post. I would like to link back to it….