We know how to create an array of (random) natural numbers and store it in a variable to use a query. Here is an example: using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
public class Exercise : Form
{
private ListBox lbxNumbers;
public Exercise()
{
InitializeComponent();
}
void InitializeComponent()
{
lbxNumbers = new ListBox();
lbxNumbers.Size = new Size(100, 140);
lbxNumbers.Location = new System.Drawing.Point(12, 12);
Text = "Numbers";
MinimizeBox = false;
MaximizeBox = false;
Controls.Add(this.lbxNumbers);
Load += new EventHandler(ExerciseLoad);
Size = new System.Drawing.Size(130, 185);
StartPosition = FormStartPosition.CenterScreen;
}
private void ExerciseLoad(object sender, EventArgs e)
{
var numbers = new int[] { 12, 44, 525, 38, 6, 28, 2448, 32, 632, 04 };
var number = from n in numbers select n;
foreach (var member in number)
lbxNumbers.Items.Add(member.ToString());
}
[STAThread]
public static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}
This would produce:
In some cases, you may want to work on a consecutive list of numbers such as 1, 2, 3, 4, 5, 6, 7, and 8. Instead of declaring a formal variable, the Enumerable class provides a method named Range that allows you to specify the first number of a range and a count of consecutive numbers to add to create a range. The syntax of the Enumerable.Range() method is: public static IEnumerable<int> Range(int start, int count); The first argument passed to this method is the beginning of the range. The second argument specifies how many numbers to add consecutively from the first. To use this method, you can declare a variable of type IEnumerable and assign a call to Enumerable.Range() that receives both arguments. Here is an example: private void ExerciseLoad(object sender, EventArgs e)
{
IEnumerable<int> range = Enumerable.Range(22, 8);
var number = from n in range select n;
foreach (var member in number)
lbxNumbers.Items.Add(member.ToString());
}
You can also declare the variable as type var. You would receive the same result:
If you want to restrict the result, you can add a where condition to it. Here is an example: private void ExerciseLoad(object sender, EventArgs e)
{
var range = Enumerable.Range(96, 10);
var number = from n
in range
where n % 2 == 0
select n;
foreach (var member in number)
lbxNumbers.Items.Add(member.ToString());
}
When you create a LINQ statement, it produces a list. Although the list is of type IEnumerable, since this is only an interface, the result relies on an actual class to provide its characteristics. The class that gives you information about a result is Enumerable. The Enumerable.Count() method is used to know the number of items in the resulting query. That method is overloaded with two versions whose syntaxes are: public static int Count<TSource>( this IEnumerable<TSource> source); public static int Count<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate); Here is an example: IEnumerable<StoreItem> sale = storeItems.Select(item => item); foreach (var item in sale) { ListViewItem lviCollection = new ListViewItem(item.ItemCode.ToString()); lviCollection.SubItems.Add(item.Category); lviCollection.SubItems.Add(item.ItemName); lviCollection.SubItems.Add(item.UnitPrice.ToString()); lvwStoreItems.Items.Add(lviCollection); } Text = "Music Store - Total Inventory: " + sale.Count().ToString() + " store items"; This would produce:
Remember that you can still use the var keyword to declare the variable that would hold the resulting list. The same var keyword can be used for the result of a method call. Here are examples: IEnumerable Since we have determined that a LINQ statement produces an Enumerable list, if you don't need the list itself, you can declare a variable that is the type returned by a method, put the statement in parentheses, and then access the method outside the closing parenthesis using the period operator. Here is an example: var total = (from staffMembers in employees orderby staffMembers.LastName select staffMembers).Count(); Remember that the IEnumerable.Count() method returns the number of items in the result of the LINQ statement, not the number of items in the original list. The following examples illustrate it: private void Exercise_Load(object sender, EventArgs e) { var students = new Student[] { . . . No Change }; IEnumerable<Student> pupils = from studs in students select studs; int boys = (from males in pupils where males.Gender == Genders.Male select males).Count(); int girls = (from females in pupils where ((females.Gender != Genders.Male) && (females.Gender != Genders.Unknown)) select females).Count(); ListViewItem lviStudent = null; ListViewGroup grpBoys = new ListViewGroup("Boys"); ListViewGroup grpGirls = new ListViewGroup("Girls"); ListViewGroup grpOthers = new ListViewGroup("Others"); foreach (var std in pupils) { if (std.Gender == Genders.Male) { lviStudent = new ListViewItem(std.StudentNumber.ToString(), grpBoys); } else if (std.Gender == Genders.Female) { lviStudent = new ListViewItem(std.StudentNumber.ToString(), grpGirls); } else { lviStudent = new ListViewItem(std.StudentNumber.ToString(), grpOthers); } lviStudent.SubItems.Add(std.FirstName); lviStudent.SubItems.Add(std.LastName); lvwStudents.Items.Add(lviStudent); lvwStudents.Groups.Add(grpBoys); lvwStudents.Groups.Add(grpGirls); lvwStudents.Groups.Add(grpOthers); } txtBoys.Text = boys.ToString(); txtGirls.Text = girls.ToString(); } This would produce:
These different techniques of calling and using the Count() method will be applied to most other methods of the Enumerable class.
If the values you are querying are numbers, you may want to find their average. To assist you, the Enumerable class provides a method named Average that is overloaded with a version for each numeric data type. The syntax for the double type is: public static double Average(this IEnumerable Here is an example of calling this method: using System; using System.Linq; using System.Drawing; using System.Windows.Forms; using System.Collections.Generic; public class Exercise : Form { private ListBox lbxNumbers; private Label lblAverage; private TextBox txtAverage; public Exercise() { InitializeComponent(); } void InitializeComponent() { lbxNumbers = new ListBox(); lbxNumbers.Size = new Size(105, 80); lbxNumbers.Location = new System.Drawing.Point(12, 12); lblAverage = new Label(); lblAverage.AutoSize = true; lblAverage.Text = "Average:"; lblAverage.Location = new Point(12, 90); txtAverage = new TextBox(); txtAverage.Width = 50; txtAverage.Location = new Point(68, 90); txtAverage.TextAlign = HorizontalAlignment.Right; Text = "Numbers"; MinimizeBox = false; MaximizeBox = false; Controls.Add(lbxNumbers); Controls.Add(lblAverage); Controls.Add(txtAverage); Load += new EventHandler(ExerciseLoad); Size = new System.Drawing.Size(140, 150); StartPosition = FormStartPosition.CenterScreen; } private void ExerciseLoad(object sender, EventArgs e) { var numbers = new double [] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; var number = from n in numbers select n; foreach (var member in number) lbxNumbers.Items.Add(member.ToString()); txtAverage.Text = number.Average().ToString(); } [STAThread] public static int Main() { System.Windows.Forms.Application.Run(new Exercise()); return 0; } } This would produce:
If it is only the average that you want, you can include the LINQ statement in parentheses and call the Average method outside. Here is an example: var average = (from n in numbers select n).Average(); txtAverage.Text = average.ToString(); Of course, you can add a where condition if you want to restrict the result. The LINQ provides many more methods for numeric values.
We have seen that a LINQ expression produces a list of values and, so far, the resulting list was stored in a variable created in a from clause. If you want, you can store the result of the LINQ expression in a specific (or external) variable. To support this, the Enumerable class provides the ToArray() and the ToList() methods. The syntax of the ToArray() method is: public static TSource[] ToArray<TSource>( this IEnumerable<TSource> source;) To store the results of an IEnumerable list in an array, declare the array variable and assign the resulting list to it. Here is an example: IEnumerable<Student> pupils = from studs in students // orderby studs.LastName //where studs.Gender == Genders.Female select studs; Student[] attendees = pupils.ToArray(); foreach (var std in attendees) { ListViewItem lviStudent = new ListViewItem(std.StudentNumber.ToString()); lviStudent.SubItems.Add(std.FirstName); lviStudent.SubItems.Add(std.LastName); lvwStudents.Items.Add(lviStudent); } Instead of first creating the select list, then declaring an array variable, you can include the LINQ statement in parentheses and call the ToArray() method outside the closing parenthesis. Here is an example: Student[] pupils = (from studs in students // orderby studs.LastName // where studs.Gender == Genders.Female select studs).ToArray(); foreach (var std in pupils) { ListViewItem lviStudent = new ListViewItem(std.StudentNumber.ToString()); lviStudent.SubItems.Add(std.FirstName); lviStudent.SubItems.Add(std.LastName); lvwStudents.Items.Add(lviStudent); } Instead of storing the result of a LINQ statement into an array, you can store it in a collection. To support this, the IEnumerable interface is equipped with the ToList() method. Its syntax is: public static List<TSource> ToList<TSource>( this IEnumerable<TSource> source); This method follows the same rules as its counterpart the ToArray() method except that you must declare a List<> generic variable for it. Here is an example: IEnumerable<Student> pupils = from studs in students // orderby studs.LastName // where studs.Gender == Genders.Female select studs; List<Student> attendees = pupils.ToList(); You can then use the List<> variable as you see fit.
In the .NET Framework, the String class starts as follows: public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string> As you can see, the String class implements:
Based on this, the String class holds a special position in LINQ. If you create a LINQ statement whose select expression produces a string value, the String class makes available its properties and methods so you can use them to refine your where statement.
We saw how you can use one value that is a member of an object of a class as produced by a select statement: var lastNames = from n in empls select n.LastName; To add other values to the select statement, that is, to access more that one member of the class, you can concatenate them. The String class provides various options. The String class is equipped with the Concat() method that is overloaded with 10 versions. You can use any of those versions to add strings. Here is an example: using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
public class Exercise : Form
{
Button btnShow;
ListBox lbxEmployees;
Employee[] employees;
public Exercise()
{
InitializeComponent();
}
void InitializeComponent()
{
employees = new Employee[10];
btnShow = new Button();
btnShow.Location = new System.Drawing.Point(12, 8);
btnShow.Width = 75;
btnShow.Text = "Show";
btnShow.Click += new System.EventHandler(this.btnShowClick);
lbxEmployees = new ListBox();
lbxEmployees.Location = new Point(12, 40);
lbxEmployees.Size = new System.Drawing.Size(180, 80);
Size = new System.Drawing.Size(210, 150);
Controls.Add(btnShow);
Controls.Add(lbxEmployees);
Text = "Employees";
}
private void btnShowClick(object sender, EventArgs e)
{
employees = new Employee[]
{
new Employee(971974, "Patricia", "Katts", 24.68M),
new Employee(208411, "Raymond", "Kouma", 20.15M),
new Employee(279374, "Hélène", "Mukoko", 15.55M),
new Employee(707912, "Bertrand", "Yamaguchi", 24.68M),
new Employee(971394, "Gertrude", "Monay", 20.55M)
};
var empls = from staffMembers
in employees
select string.Concat(staffMembers.EmployeeNumber.ToString(), ", ",
staffMembers.FirstName, " ",
staffMembers.LastName, ", ",
staffMembers.HourlySalary.ToString());
foreach (var empl in empls)
lbxEmployees.Items.Add(empl);
}
[STAThread]
public static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}
public class Employee
{
public int EmployeeNumber;
public string FirstName;
public string LastName;
public decimal HourlySalary;
public Employee(int number = 0,
string firstName = "John",
string lastName = "Doe",
decimal salary = 0M)
{
EmployeeNumber = number;
FirstName = firstName;
LastName = lastName;
HourlySalary = salary;
}
internal string GetFullName()
{
return LastName + ", " + FirstName;
}
}
This would produce:
Alternatively, you can use the + operator that is overloaded in the String class. Here is an example: using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace LINQFundamentals
{
public class Employee
{
public int EmployeeNumber;
public string FirstName;
public string LastName;
public double HourlySalary;
}
public partial class Exercise : Form
{
public Exercise()
{
InitializeComponent();
}
private void btnShow_Click(object sender, EventArgs e)
{
var empls = new Employee[5];
. . . No Change
var fullNames = from n
in empls
select n.LastName + ", " + n.FirstName;
foreach (var member in fullNames)
lbxEmployees.Items.Add(member);
}
}
}
This would produce:
In the same way, you can use any of the regular C# operators to produce any result of your choice. Two other options consist of using either the Format() of the Join() methods (of the String class).
Like all classes of the .NET Framework, the String class inherits the Equals() method of the Object class. This makes it possible to compare two strings for equality. Besides the Equals() method, the == operator is overloaded in the String class and has the same effect. Here is an example of using it: private void Exercise_Load(object sender, EventArgs e)
{
var names = new[]
{
"Hermine", "Patrick", "Hank", "Bertine",
"Julius", "Thomas", "Jeannette", "Patrick",
"Patrick", "Raul", "David", "Paulette"
};
var name = from n
in names
where n == "Patrick"
select n;
foreach (var member in name)
lbxNames.Items.Add(member);
}
This would produce:
If you are working on a class, you can apply the equality operator on one of its properties. Here is an example: private void btnShowClick(object sender, EventArgs e) { employees = new Employee[] { new Employee(971974, "Patricia", "Katts", 24.68M), new Employee(208411, "Raymond", "Kouma", 20.15M), new Employee(279374, "Hélène", "Mukoko", 15.55M), new Employee(707912, "Bertrand", "Yamaguchi", 24.68M), new Employee(294800, "Peter", "Mukoko", 18.85M), new Employee(971394, "Gertrude", "Monay", 20.55M) }; var fullNames = from empls in employees where empls.LastName == "Mukoko" select empls.LastName + ", " + empls.FirstName; foreach (var empl in fullNames) lbxEmployees.Items.Add(empl); } This would produce:
On the other hand, to find out if two strings are not equal, you can use the != operator.
The String class is equipped with various types of methods to work on sub-strings. To get a list of strings that start with a certain letter or a sub-string, you can call the StartsWith() method. This is a Boolean method that is overloaded with three versions. One of the versions takes one argument that is the sub-string to find at the beginning of the string that calls it. Here is an example: private void Exercise_Load(object sender, EventArgs e) { var name = new[] { "Hermine", "Patrick", "Hank", "Bertine", "Julius", "Thomas", "Jeannette", "Patricia", "Henriette", "Raul", "David", "Paulette" }; var names = from n in name where n.StartsWith("P") select n; foreach (var member in names) lbxStrings.Items.Add(member); } This would produce:
The String.StartsWith() method returns true if the variable that called it starts with the argument. You can negate the result to find the strings that don't start with the argument. To do this, apply the ! operation. Here is an example: private void Exercise_Load(object sender, EventArgs e)
{
var name = new[]
{
"Hermine", "Patrick", "Hank", "Bertine",
"Julius", "Thomas", "Jeannette", "Patricia",
"Henriette", "Raul", "David", "Paulette"
};
var names = from n
in name
where !n.StartsWith("P")
select n;
foreach (var member in names)
lbxNames.Items.Add(member);
}
This would produce:
To make the expression easy to read, you should include it in parentheses. Here is an example: private void Exercise_Load(object sender, EventArgs e) { var name = new[] { "Hermine", "Patrick", "Hank", "Bertine", "Julius", "Thomas", "Jeannette", "Patricia", "Henriette", "Raul", "David", "Paulette" }; var names = from n in name where !(n.StartsWith("P")) select n; foreach (var member in names) lbxNames.Items.Add(member); }
To get a list of strings that end with a certain letter or sub-string, you would call the String.EndsWith() method. Here is an example: private void Exercise_Load(object sender, EventArgs e) { var name = new[] { "Hermine", "Patrick", "Hank", "Bertine", "Julius", "Thomas", "Jeannette", "Patricia", "Henriette", "Raul", "David", "Paulette" }; var names = from n in name where n.EndsWith("ette") select n; foreach (var member in names) lbxStrings.Items.Add(member); } This would produce:
To negate this operation, apply the ! operator to it.
In the same way, to get a select list of strings that contain a certain symbol or a sub-string, you can call the String.Contains() method as follows: private void Exercise_Load(object sender, EventArgs e) { var name = new[] { "Hermine", "Patrick", "Hank", "Bertine", "Julius", "Thomas", "Jeannette", "Patricia", "Henriette", "Raul", "David", "Paulette" }; var names = from n in name where n.Contains("au") select n; foreach (var member in names) lbxStrings.Items.Add(member); } This would produce:
Because the String.Contains() method is Boolean, to negate its result, you can precede it with the ! operator. |
|
|||||||||||||||||||||||||||
|