November 19, 2009

Sample Linq

In order to use Linq in the following ways a reference to the 'System.Core' assembly is required. The namespace is 'System.Linq'.
Useful Links
This code shows the same method 3 times using different forms of Linq. It also demonstrates some lambda expressions.
private Smeg FindSmeg(Project project, string smegName)
{
    SpellRoot spellRoot = SpellRoot.Get(project);
    SmegCollection smegs = spellRoot.SmegCollection;

    // Note that the 'smegVar' is an IEnumerable 
    var smegVar = from bh in smegs
                      where bh.Name.Equals(smegName,   
                                StringComparison.OrdinalIgnoreCase)
                      select bh; 
    Smeg smeg = smegVar.FirstOrDefault();

    return smeg;
}

private Smeg FindSmeg2(Project project, string smegName)
{
    SpellRoot spellRoot = SpellRoot.Get(project);
    SmegCollection smegs = spellRoot.SmegCollection;

    // Declaring a Func type lambda expression
    // A good way to learn how to form correct lambda expressions
    Func smegSelector = 
        bh => bh.Name.Equals(smegName, StringComparison.OrdinalIgnoreCase);
    Smeg smeg = smegs.FirstOrDefault(smegSelector);

    return smeg;
}

private Smeg FindSmeg3(Project project, string smegName)
{
    SpellRoot spellRoot = SpellRoot.Get(project);
    SmegCollection smegs = spellRoot.SmegCollection;

    // Inline lambda expression
    Smeg smeg = smegs.FirstOrDefault(
        bh => bh.Name.Equals(smegName, StringComparison.OrdinalIgnoreCase));

    return smeg;
}

Simple examples

Count() - Get count of items in an enumeration
IEnumerable smegs = ...
int count = smegs.Count();
ToArray() - enumeration to an array
IEnumerable smegs = ...
Smeg smegArr = smegs.ToArray();
ToList() - enumeration to a list
IEnumerable smegs = ...
IList smegList = smegs.ToList();
Where() - This is a general purpose filter, the function in the Where clause performs the filtering
File.ReadLines( @"D:\Users\ukrb\Docs\SpcPressures.txt" ).
    Where(li => li.Contains(" PRESSURE")). // Filter out any line NOT containing the specified string (" PRESSURE")
    Dump();
Select() - Allows you to Select portions of/Convert each enumerated item to an item of another type (not by casting but by extraction or conversion). Anonymous types can be used for conversion to simple intermediate types
// This parses a file of data where each line contains a number of samples, their average, maximum, minimum, etc.
File.ReadLines( @"D:\Users\ukrb\Docs\PRESSURE 214289.DAT" ).
    Select(li => ParseLine(li)).   // ParseLine is a function returning a specific class type instance
    Select(pe => pe.ToV10Form()).  // Now convert it to another more readable string of only data that is interesting
    Dump(); 
Single() - Returns the single matching element in the enumeration, if there is not exactly one match an 'InvalidOperationException' exception is thrown.
IEnumerable smegs = ...
Smeg first = smegs.Single();
First() - first element in an enumeration, be careful an exception is thrown if the enumeration is empty! If your enumeration maybe empty use FirstOrDefault
IEnumerable smegs = ...
Smeg first = smegs.First();
FirstOrDefault() - first element in an enumeration, and when it is empty, the default value of the enumerated type (which is always null for a reference type)
IEnumerable smegs = ...
Smeg first = smegs.FirstOrDefault();
Last() - last element in an enumeration, be careful an exception is thrown if the enumeration is empty!
IEnumerable smegs = ...
Smeg last = smegs.Last();
Skip() - skip the first n elements in an enumeration and return what is left, be careful an exception is thrown if the enumeration has less than n items
string[] allArgs = Environment.GetCommandLineArgs();
IEnumerable<string> args = allArgs.Skip(1); // First argument is the exe path
OfType() - extract from an enumeration all objects of the given type. Safe way of converting an enumeration of one type to another, it uses the 'is' operator. An excellent way to filter out null objects in a sequence. There is the "Cast<>()" operator but the trouble with this is that it will throw an exception if one of the objects of the enumeration is not of the given type so only use that when you know that all the elements of the enumeration will cast to the new type
IEnumerable smegs = ...
int numSquares = smegs.OfType().Count();
Cast() - Casts all items in the enumeration to the given type. When an item can not be cast to the new type then an exception is thrown. Useful to convert old style enumerables of known types. For example:
StringCollection sc = this.settingsService.GetProperty
      <StringCollection>(SourceDirectoriesSetting) ?? new StringCollection();
if (sc.Count > 0)
{
  // Cast the string collection 'sc' entries to strings
  ObservableCollection<string> oc = new ObservableCollection<string>(sc.Cast<string>());
  ...
}
Using the XXXOrDefault (First, Single, Last, ElementAt) option:
In some cases when an IEnumerable returns no entries at all the Linq operator will throw an exception using the "OrDefault" option will circumvent this problem. In the case that there are no entries returned from an XXXOrDefault operator, Linq will return the default value for the generic parameter. In the case of a reference type this will be null. For a value type it will return the default value for that value type.

SelectMany() - SelectMany flatten nested enumerables, see here for a good example

Linq Set operators:
  • Union - Simply appends one IEnumerable to another
  • Intersect - Finds items common to 2 IEnumerables
  • Except - Subtracts one IEnumerable from another
  • Distinct - Removes duplicate items from a single IEnumerable (Operates on a single IEnumerable!)

No comments: