Using LINQ in C#

The demonstrations were first published under the title Getting Started with LINQ using RemObjects C#. We provide here versions that compile in both RemObjects C# and SharpDevelop.

LINQ (Language-Integrated Query) is a powerful feature of C# that allows you to use SQL-like statements to query several forms of data. Here we give examples of LINQ applied to arrays of strings and of objects and to a string list. We also provide a demonstration of its application to data in XML files.

The first example shows the difficult but concise syntax for querying an array of string with lambdas and the easier syntax (closer to conventional SQL) applied to a list of strings. See further examples of the use of lambda expressions below it. A copy of the output follows the code.

using System;
using System.Collections.Generic;
using System.Linq;

//Adapts code from http://www.codeproject.com/Tips/590978/LINQ-Tutorial-for-Beginners
namespace LINQ_Demo1
{
  static class Program
  {
    public static void Main(string[] args)
    {
      string[] numbers = {"24", "18", "2", "49", "13", "33"}; 
      //Difficult but concise syntax using lambda expressions     
      int[] nums = numbers.Select(s => Int32.Parse(s)).OrderBy(s => s).ToArray();
      foreach (int num in nums)
        Console.Write(num.ToString() + " "); 
      List<string> colours = new List<string>(new String[]{"red", "orange", "yellow", "green"});
      //Easier syntax, closer to conventional SQL
      IEnumerable<string> ieColours = from col in colours where col.Length == 6 orderby col select col;
      Console.WriteLine("\nSix-lettered colours in alphabetical order:");
      foreach (string colour in ieColours) 
        Console.WriteLine(colour); 
      colours.AddRange(new String[]{"blue", "indigo", "violet"}); 
      Console.WriteLine("Three colours added to array"); 
      Console.WriteLine("Six-lettered colours in alphabetical order:");
      foreach (string colour in ieColours) //IEnumerable ieColours is re-evaluated
        Console.WriteLine(colour);
      Console.ReadLine();
    }
  }
}

Output:
2 13 18 24 33 49
Six-lettered colours in alphabetical order:
orange
yellow
Three colours added to array
Six-lettered colours in alphabetical order:
indigo
orange
violet
yellow

Using LINQ with Objects

The next example shows how to handle an array of objects. A copy of the output follows the code.

using System;
using System.Linq;
using System.Xml;
using  System.Xml.Linq;
using System.Text;

namespace LINQ_ObjectArray
{
  class Player
  {
    private String name;
    private  Single points;

    public Player(String forename, Single pts)  
    {
      this.name = forename;
      this.points = pts;
    }

    public  string GetName()
    {
      return this.name;
    }

    public void ShowPoints()
    {
      Console.WriteLine("Points for " + this.GetName() + ": {0:0.0}", this.GetPoints());
    }

    public Single GetPoints()
    {
      return this.points;
    }
  }

  static class Program
  {
    public static void Main(string[] args)
    {
      Player[] players = new Player[4]{new Player("Jo", 5.0f), new Player("Jim", 7.1f),
                                       new Player ("Laura", 8.2f), new Player("Izzy", 6.9f)};    	
      foreach (Player p in players)
        p.ShowPoints();
      var highscorers = from p in players where p.GetPoints() > 7 select p.GetName();
      Console.WriteLine("Players with more than 7 points:"); 
      foreach (var highscorer in highscorers)
        Console.WriteLine(highscorer);
      string initial = "J";
      var jnames = from p in players where p.GetName()[0] == initial[0] select p.GetName();
      Console.WriteLine("Players with names beginning with J:"); 
      foreach (var jname in jnames)
        Console.WriteLine(jname);
      Console.ReadLine();
    }
  }
}

Output:
Points for Jo: 5.0
Points for Jim: 7.1
Points for Laura: 8.2
Points for Izzy: 6.9
Players with more than 7 points:
Jim
Laura
Players with names beginning with J:
Jo
Jim

Oxygene Demo converted to C#

The demo shows one straightforward query and a complex one. A copy of the output follows the code.

using System;
using System.Linq;

namespace LinqToObjects
{
  public class Words
  {
    private String[] words =  {"hello", "Oxygene", "wonderful", "linq", "beautiful", "world"};
    public void SimpleSelect()
    {
      var shortwords = from word in words
                       where word.Length <= 5
                       select word;

      Console.WriteLine("Simple select statement\n");
      foreach (string word in shortwords) 
        Console.WriteLine(word);
    }

    public void  ComplexSelect()
    {
      var groups = from word in words
                   orderby word ascending
                   group word by word.Length into lengthGroups
                   orderby lengthGroups.Key descending
                   select new {Length = lengthGroups.Key, Words = lengthGroups};

      Console.WriteLine("Complex query using group and order\n");
      foreach (var grp in groups)
      { 
        Console.Write("Words of length " + grp.Length + ": ");
        foreach (string word in grp.Words)
        {
          Console.Write(word + " ");
        }
        Console.WriteLine();
      }
    }
  }
  static class Program
  {
    public static void Main(string[] args)
    {
      Words words = new Words();
      words.SimpleSelect();

      Console.WriteLine("\n");
      words.ComplexSelect();

      Console.WriteLine("\n");
      Console.Read();
    }
  }
}

Output:
Simple select statement

hello
linq
world


Complex query using group and order

Words of length 9: beautiful wonderful
Words of length 7: Oxygene
Words of length 5: hello world
Words of length 4: linq

Further Examples of Lambdas

We have converted an Oxygene language demo to C# to show you further examples of the use of lambda expressions. A copy of the output follows the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LambdasDemo
{
  public class Person
  {
    public string Name {get;set;}
    public int Age {get;set;}
    public Person(string setName, int setAge)
    {
      Name = setName;
      Age = setAge;
    }
  }

  public class Program
  {
    private List<Person> persons;
    public void FillPersons()
    {
      persons = new List<Person>();
      persons.AddRange( new Person[] {new Person("John Smith", 35), new Person("Lara Croft", 33), new Person ("Nancy Davolio", 22),
                        new Person ("Andrew Fuller", 30), new Person ("Janet Leverling", 26), new Person ("Margareth Peacock", 18),
                        new Person ("Steven Buchanan", 19), new Person ("Laura Callahan", 55), new Person ("James Bond", 29)});
    }
  
    public static void Main(string[] args)
    {
      Console.WriteLine("Lambdas example\n");
      Program MyProg = new Program();
      MyProg.FillPersons();
      MyProg.Test();
      Console.ReadLine();
    }
    
    public void Test()
    {
      //Lambda expressions may be used for specifying parameters of actions.
      Action<string> printOut = s => Console.WriteLine(s);

      //Multi-parameter lambda
      Action<string, string> printTwoStrings = (s1, s2) => Console.WriteLine(s1 + s2);

      persons.Sort((p1, p2) => p1.Name.CompareTo(p2.Name));

      //The result is sequence of values such as "John Smith (35)".
      var personsNameAge = persons.Select(p => p.Name + " (" + p.Age.ToString() + ")");

      printOut("People:");
      foreach (var p in personsNameAge)
        printOut(p.ToString());
      int averageAge = SumAge() / persons.Count;

      printTwoStrings("\nThe average age is: ", averageAge.ToString());

      //Lambda expressions are most notably used with query operators.
      var youngPersons = persons.Where(p => p.Age < 30).OrderBy(p => p.Age);

      printOut("\nPeople younger then 30, sorted by age:");
  
      foreach (var p in youngPersons)
        printTwoStrings(p.Name, " (" + p.Age.ToString() + ")");
    }

    public int SumAge()
    {
      int sum  = 0;
      foreach (var p in persons)
          sum += p.Age;
      return sum;
    }    
  }
}

Output:
Lambdas example

People:
Andrew Fuller (30)
James Bond (29)
Janet Leverling (26)
John Smith (35)
Lara Croft (33)
Laura Callahan (55)
Margareth Peacock (18)
Nancy Davolio (22)
Steven Buchanan (19)

The average age is: 29

People younger then 30, sorted by age:
Margareth Peacock (18)
Steven Buchanan (19)
Nancy Davolio (22)
Janet Leverling (26)
James Bond (29)

LINQ applied to XML

This last example shows how to:
  • interrogate a string copied from an XML file;
  • save data as an XML file;
  • load an XML file and interrogate it.
The code follows a copy of the output.

Output:
Book(s) by Amis:
Yellow Dog
Surnames of author(s) with forename Samuel:
Beckett

using System;
using System.Linq;
using System.Xml;
using  System.Xml.Linq;

namespace LINQ_XML_Demo
{
  static class Program
  {
    public static void Main(string[] args)
    {
      //Use XML data copied to a string.
      XElement books = XElement.Parse(
          @"<books>
              <book>
                <title>On Chesil Beach</title>
                <author_surname>McEwan</author_surname>
                <author_forename>Ian</author_forename>
              </book>
              <book>
                <title>Yellow Dog</title>
                <author_surname>Amis</author_surname>
                <author_forename>Martin</author_forename>
              </book>
              <book>
                <title>Malone Dies</title>
                <author_surname>Beckett</author_surname>
                <author_forename>Samuel</author_forename>
              </book>
            </books>");

      var titles = from book in books.Elements("book")
                   where (string)book.Element("author_surname").Value == "Amis"
                   select book.Element("title");
      Console.WriteLine("\nBook(s) by Amis:"); 
      foreach (var title in titles)
      {
        Console.WriteLine(title.Value);
      }
      //Create an xml document and save it to file.
      XDocument doc = new XDocument(
        new XDeclaration("1.0", "utf-16", "false"),
        new XElement("books",
          new XElement("book",
            new XElement("title", "On Chesil Beach"),
            new XElement("author_surname", "McEwan"),
            new XElement("author_forename", "Ian")),
          new XElement("book",
            new XElement("title", "Yellow Dog"),
            new XElement("author_surname", "Amis"),
            new XElement("author_forename", "Martin")),
          new XElement("book",
            new XElement("title", "Malone Dies"),
            new XElement("author_surname", "Beckett"),
            new XElement("author_forename", "Samuel"))));
      doc.Save("books.xml");
      //Now load the file we have saved.
      XDocument doc2 = XDocument.Load("books.xml");
 
      var surnames = from book in doc2.Root.Descendants("book")
                     where (string)book.Element("author_forename").Value == "Samuel"
                     select book.Element("author_surname");
      Console.WriteLine("Surnames of author(s) with forename Samuel:");
      foreach (var surname in surnames)
      {
        Console.WriteLine(surname.Value);
      }
      Console.ReadLine();
    }
  }
}
The saved XML file is as follows.
<?xml version="1.0" encoding="utf-16"?>
<books>
  <book>
    <title>On Chesil Beach</title>
    <author_surname>McEwan</author_surname>
    <author_forename>Ian</author_forename>
  </book>
  <book>
    <title>Yellow Dog</title>
    <author_surname>Amis</author_surname>
    <author_forename>Martin</author_forename>
  </book>
  <book>
    <title>Malone Dies</title>
    <author_surname>Beckett</author_surname>
    <author_forename>Samuel</author_forename>
  </book>
</books>
Programming - a skill for life!

C# Demonstrations of I/O, arrays, methods, classes, loops, enums, pointers, file handling, Firebird databases, LINQ and drawing on a form