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! Also, if you like this article, you may like my next article, Extended LINQ: additional operators for LINQ to objects.
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 = 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:
- Extended LINQ: additional operators for LINQ to objects [igoro.com]
- LINQ in Action [Book by Fabrice Marguerie]
- C# in Depth: What you need to master C# 2 and 3 [Book by Jon Skeet]
Tags: LINQ
Great post.
I would suggest change 4) to this one :
string values = string.Join(string.Empty, Enumerable.Repeat(pattern, N).ToArray());
You can pass “ABC” as pattern and you will have the same result but if you want to have LinqLinqLinq my snippet will help. String is more generic than char
Just my 2 cents
Your list->list cast could be:
List strList = …;
List objList = strList.Cast().ToList();
or even nicer with ‘var':
…
var objList = strList.Cast().ToList();
D’oh – angle brackets were removed You get the idea though
Petar, Chris: thanks for your ideas! I will add them into the posting later today.
Cool! I like the array.Concat one. I wrote an article about Enumerable.Repeat–it is my very favorite LINQ expression of this type
[…] 7 tricks to simplify your programs with LINQ – Igor Ostrovsky has a nice write up of 7 programming improvements made possible by LINQ […]
Another way to cast objects is with “OfType” operator. With “Cast” operator an exception
is thrown if any object is unable to be cast to the specified data type. Instead with OfType operator only objects of the specified type will be stored in the output IEnumerable .
ex. List ls = new List(.OfType());
Best regards
Giuliano
Sorry i forgot about the code tags
List<object> ls = new List<object>(strList.OfType<object>());
good tips I think it is convient for us to use it for some simple factors
Nice post.
Somewhat similar, but writing some extension methods to do much the same in a ‘fluent’ style (in the Fowler sense):
http://mikehadlow.blogspot.com.....-with.html
And with strings:
http://mikehadlow.blogspot.com.....tring.html
I don’t know what code will look like when I post but I exchanged lt and gt with a low bar ‘_’ and curly bractets with ‘curly’ just bo be sure. ;~)
I like this little extension very much. Now I don’t have to write the foreachs all the time. Once is enough!
public static void ForEach_T_(this IEnumerable_T_ set, Action_T_ action)
curly
foreach (var t in set)
action(t);
endcurly
Thanks for all of the insightful comments!
Sorry about all the HTML-related trouble with posting comments. I definitely need a Preview Comment button or something. I am looking for a WordPress plugin to fix this.
Igor
Nice post, however, I think the title of this article is misleading. I think the title would be closer to “7 Tricks… with Langauge Extensions” rather than “… LINQ”. LINQ uses many of the language extensions in the new framework, but using them by themselves does not constitute “using LINQ”. Possibly nit-picky, but I believe it sends the wrong message as to what LINQ really is.
Jayson: Thanks for reading!
The article talks about interesting ways of using LINQ operators (Select, Repeat, Concat…), so it really is about LINQ. It is true that my code samples use some C# 3 features like extension methods and lambda expressions. But, each sample could also be reimplemented without these features, or even in any other .Net language. So, it is not language itself that is of interest here. It is the different LINQ operators, and what you can do with them.
However, I do agree that I could have made the title more specific. To be completely accurate, the article should be called “7 tricks to simplify your programs with LINQ to objects”, but I decided against this for readability reasons.
[…] LINQ: additional operators for LINQ to objects In responses to my last week’s post, several readers mentioned LINQ-like operators they implemented themselves. I also had ideas for […]
I loved your tricks. This is the good message : Linq is not just a way to write SQL queries in C# code, Linq is a beautiful technology every developer can use in a lot of situations.
The trick about subset is certainly, on the syntax side, the most “perverse” of the 7, but is a good demo of what Linq can bring to the developer who want to go further.
As I’m collecting such tricks to explain Linq in my country (France), I wrote a post showing some of your tricks plus a console demo project to download.
Of course I mentionned your name and your blog more than once, even if most of my readers prefer french blogs (this is not a legend, speaking foreign languages is not the thing that frenchies do best …).
Thanks for this post.
Great post, thanks for the tips.
[…] 7 façons de simplifier votre code avec LINQ: Igor Ostrovsky à un excellent article qui parle de nouvelles techniques que vous pouvez utiliser afin d’améliorer votre code en utilisant .NET 3.5 et les nouvelles fonctionnalités du langage et de LINQ. […]
Very nice!!!! Great post. I would also include the reference from linqhelp.com on Adding to a Database using LINQ. Very easy and simple to use! Thanks!
Is there a way to simplify the Linq Lambda Expressions syntax in a function call? The problem I am trying to solve is that properties cannot be passed in by ref like variable would e.g. MyFunction(ref double anyVariable). Linq Lambda Expressions allow Strongly type property names (see http://discuss.joelonsoftware......2.593055.7).
A typical Linq Lambda Expression function call looks like:
LinqProperty((MyClass => obj.MyProperty), i);
Where the function, class and property are defined as:
static void LinqProperty(Expression<Property> expression, Tp anotherValue)
{
}
class MyClass
{
public int MyProperty { get; set; }
}
It would be nice if the compiler could infer the types so the class type and property type would not have to be explicitly declared in the template:
LinqProperty ((MyClass => obj.MyProperty), i);
But this causes an error: The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly.
Randy: Unfortunately, I don’t understand what you are trying to do.
The C# compiler will only translate a lambda expression into an expression tree if it is assigned into a variable whose type is Expression<Func<T>>. Perhaps try to change the signature of LinqProperty as follows:
static void LinqProperty<T>(Expression<Func<T>> expression, T anotherValue)
What I’d like to do is create a property helper function. Ideally I would pass the property in by reference so I could assign the new value only after it is validated, etc. Passing a property in by reference is not possible because only variables can be passed in by reference. For example, when I have a class with a property:
class MyClass
{
public int MyProperty { get; set; }
}
I get an error “A property or indexer may not be passed as an out or ref parameter”:
static void Main()
{
MyClass obj = new MyClass();
UpdatePropertyRef(ref obj.MyProperty, 123);
}
static void UpdatePropertyRef(ref Tv refProperty, Tv newValue)
{
refProperty = newValue;
}
I can create a helper function with Linq Lambda Expressions:
static void UpdatePropertyLinq(Expression<Property> expression, Tv newValue)
{
}
Unfortunately the usage looks complicated, which makes it undesirable for a helper function for other people to use:
static void Main()
{
MyClass obj = new MyClass();
UpdatePropertyLinq((MyClass => obj.MyProperty), 123);
}
Is there a way create a helper function with a simpler calling syntax utilizing Linq Lambda Expressions (or any other means)?
A VERY important note: using Enumberable.Repeat with reference types may not work as you expect. Check this post for details: http://trycatchfail.com/blog/p.....rrays.aspx
[…] 7 Ways to Simplify your code with LINQ: Igor Ostrovsky has a great blog post that talks about new code techniques you can use to improve your code using .NET 3.5 and the new language and LINQ features in it. […]
Hi,
It is a very good post
[…] 7 Tricks to Simplify Your Programs with LINQ: Think LINQ is just for databases? If so, you are quite wrong! Igor Ostrovsky has put together an excellent post outlining simple, yet effective, ways to use LINQ to simplify your code. A great primer for the latest and greatest from Redmond! […]
[…] 7 tricks to simplify your programs with LINQ | Igor Ostrovsky Blogging Possibly related posts: (automatically generated)How to use Aggregate functions with LINQ to […]
[…] Initialize an array […]
Can you help me understand or point me in the right direction to solve my issue. I’m trying to subgroup a Datatable(all I am given) using LINQ. I am trying to go several layers deep(5).
I have tried several things but everything falls apart after three levels. I’m sure I just don’t understand it that well yet. I have tried:
var query = from nRow in newDT2.AsEnumerable()
group nRow by nRow.Field(“agency_group”) into agency_group
select new
{
ag = agency_group.AsEnumerable(),
agK = agency_group.Key,
agency_names =
from agency_names in agency_group
group agency_names by agency_names.Field(“agency_name”) into agency_names_group
select new
{
an = agency_names_group.AsEnumerable(),
anK = agency_names_group.Key,
div_depts =
from div_depts in agency_names_group
group div_depts by div_depts.Field(“div_dept”) into div_depts_group
select new
{
dd = div_depts_group.AsEnumerable(),
ddK = div_depts_group.Key,
unit_sections =
from unit_section in div_depts_group
group unit_section by unit_section.Field(“unit_section”) into unit_section_groups
select new
{
us = unit_section_groups.AsEnumerable(),
usK = unit_section_groups.Key,
group_unit_req =
from gur in unit_section_groups
group gur by gur.Field(“group_unit_requirement”)
}
}
}
};
and
var query = from nRow in newDT.AsEnumerable()
group nRow by nRow.Field(“agency_group”) into agency_group
from agency_name in
(from nRow in agency_group
group nRow by nRow.Field(“agency_name”) into agency_name_group
from division_name in
(from nRow in agency_name_group
group nRow by nRow.Field(“div_dept”))
group division_name by agency_name_group)
group agency_name by agency_group;
But something just isn’t working for me. I’ve looked all over and can’t find anything that goes that deep. Any help you can provide is greatly appreciate.
Have a good day.
Hi Polo H,
What exactly isn’t working for you? Do you get exceptions? Or compile errors? Or wrong results?
It is hard to tell from the complex query what your problem may be.
Hi Igor,
This is cool. I never thought Linq was so rich with enumarable manipulation. I was so ‘stick’ to C++ pointers model and C# foreach..loop. Now I need to change my paradigm for arrays using Linq. Nice article.
[…] notation for usual procedures (searching, looping, replacing etc.) is possible. See this handy post for more on LINQ […]
Another way to concat string from the chars sequence:
xs.Aggregate(new StringBuilder(), (b, c) => b.Append(c), b => b.ToString())
Maybe it’s performance better than suggested string.Join() or string(char[]) ctor usages…
[…] 7 tricks to simplify your programs with LINQ LINQ Learning Guide: LINQ to SQL […]
[…] 7 Ways to Simplify your code with LINQ: Igor Ostrovsky has a great blog post that talks about new code techniques you can use to improve your code using .NET 3.5 and the new language and LINQ features in it. […]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CALINQ1
{
class clsemployee5
{
public int pempid
{set; get;}
public string pename
{set;get;}
public string pdesignation
{set;get;}
public DateTime pdoj
{set;get;}
public Double psal
{set;get;}
public int deptno
{set;get;}
}
class clsemployee14
{
static void Main(string[] args)
{
List emplist = new List()
{
new clsemployee5{pempid=101,pename=”shiva”,pdesignation=”ceo”,pdoj=23/07/1981,psal=10000,deptno=10}
};
Console.WriteLine(“employee list is:-“);
foreach(var i in emplist)
Console.WriteLine(i.pempid+” “+i.pename+” “+i.pdesignation+” “+i.pdoj+” “+i.psal+” “+i.deptno);
Console.Read();
}
}
}
In the above programme doj will not be print……what is the error????
Because 23/07 is 3, and 3/1981 is 0;
You cannot convert 0 to DateTime
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];
sir can u explain me this code ,i don understand flow for this query which query will execute either outer one or inner one….plz explain in breif if possible send me some written demo on my mail sunnyspydee@gmail.com
Outstanding info over again! I am looking forward for your next post;)
still news about LINQ, is this new programming language?
Great post, keep on posting the tricks
Hi Igor,
What a great post, I have forwarded the URL to all my team members!
I have noticed that item 5) [while still immensely useful] might be obsolete given the advent of Covariance and Contravariance of generic type parameters in C# 4.0.
// A collection declared to contain elements of a derived type, Spoon.
List<Spoon> spoonList = new List<Spoon> { ... };
// A distribution station handling any IUtensil type
IFacility<IUtensil> facility = new CanteenFacility<IUtensil>();
facility.Distribute(spoonList);
[…] Někdy se může hodit pattern pro spočítání geometrické řady. Obzvláště pokud počítáte zůročení atd… Problém funkce Aggregate je v tom, že vrací pouze jeden výsledek. U geometrické řady však potřebujete výpočet nad všemi předešlými prvky, toho dosáhnete pomocí funkce Range. Mnoho hezkých příkladů pro použití Enumerable naleznete zde. […]
Good one. My favorite of LINQ is to convert collection to the sequence.