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
- interrogate a string copied from an XML file;
- save data as an XML file;
- load an XML file and interrogate it.
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>