supports the common APIs provided by the collection interface
System.Linq.Enumeralbe class for standard query operators to perform collection processing
1, anonymous type
2, local variables of the hidden type
3, collection initializer
4, set
5, standard query operator
&NBSP
This chapter discusses the generic collection interface. The
Non-generic Collection class.
First, anonymous type, and implicitly typed local variable declarations
c#3.0 enhanced.
1, anonymous type
A special type of data that is ultimately declared by the compiler and not by a well-defined class.
Similar to anonymous functions, when the compiler sees an anonymous type, it automatically performs some background operations to generate the necessary code,
allowing it to be used as explicitly declared.
Class program { static void main (String[] args) { var patent1 = new { Title = "Xxm1", YearOfPublication = "1977"
}; var patent2 = new {
Title = "XXM2",
yearofpublication = "1978" }; var patent3 = new { patent1.
Title, //Rename Property year = patent2.
Yearofpublication }; console.writeline (patent1. title + ":" + patent1.
Yearofpublication); &nbsP; console.writeline (Patent2. title + ":" + patent2.
Yearofpublication); console.writeline (Patent3. title + ":" + patent3.
year);
console.writeline ();
console.writeline (PATENT1);
console.writeline (Patent2);
console.writeline (PATENT3);
console.readline (); } }
Output:
xxm1:1977
xxm2:1978
xxm1:1978
{Title = xxm1, yearofpublication = 1977}
{Title = xxm2, yearofpublication = 1978}
{Title = xxm1, year = 1978}
Anonymous types are entirely implemented by the C # compiler, and do not have an explicit implementation within the runtime.
Specifically, when the compiler encounters an anonymous type of syntax, a CIL class is automatically generated,
The values and data types that are named in their properties and anonymous type declarations correspond.
2. Implicitly typed Local variables
Because anonymous types are not named by definition, it is not possible to explicitly declare a local variable to be an anonymous type.
Instead, the type of the local variable is substituted for var.
If an anonymous type is assigned to an implicitly typed variable, then in the CIL code generated for the local variable, its data type is
Compiler-generated type, similarly, if a string is assigned to an implicitly typed variable, then in the resulting CIL, its data type is
String In fact, for an implicitly typed variable, if it is assigned a non anonymous type such as String, then the resulting CIL code and
There is no difference between declaring a string type directly.
String Text= "This is a test of the ...";
var text= "This is a test of the ...";
The CIL code that the two statements eventually generate is exactly the same.
Although the anonymous type of C # does not have a name available, it is still strongly typed.
For example, the attributes of a type are fully accessible.
For anonymous types, it is not possible to specify a data type, so you must use Var.
3. More considerations for anonymous types and implicit local variables
When an anonymous type is declared, the name does not need to be specified (or specified) if the assignment is a property or a field call.
Such as
var patent3 = new
{
patent1. Title,
//renaming attribute Year
= Patent2. Yearofpublication
};
If the property names and order of the two anonymous types and the data types match exactly, the system compiles at compile time for only the two
An anonymous type declaration generates a data type.
Therefore, the type is compatible only if the property name, data type, and property order exactly match.
An anonymous type is immutable, and once instantiated, changing one of its properties will generate a compilation error.
When declaring a method, it is not possible to decorate one of its arguments to declare an implicit data type (VAR).
Within the method that creates the anonymous type, an instance of an anonymous type can be passed outside the method only in two ways.
First, if the parameter of the method is of type object, an instance of the anonymous type can be passed outside the method because the anonymous type will be converted incognito.
The second way is to use method type derivation, in which case an instance of an anonymous type is passed in the form of a method's "type parameter".
The compiler can successfully derive a specific type.
So, using function (PATENT1) to invoke void method The (t parameter) succeeds in compiling, although within the function (),
parameter allows only those operations supported by the object. The
Anonymous type is the key to c#3.0 support for "projection."
Generation of anonymous types:
Although Console.WriteLine (patent1) calls ToString () by default, the anonymous type's ToString () has been overridden,
The compiler overridden the ToString () method when generating code for an anonymous type. Similarly, the implementations of Equals () and GetHashCode () are also important in the generated type.
So, once the order of the attributes changes, a new data type is generated that eventually builds.
If this is not the case, instead of generating the same type for two anonymous types with different attribute order,
a change in the order of the attributes results in an explicit, even potentially unacceptable, effect on the ToString () output of another implementation.
In addition, when a program executes, it is possible to reflect a type and check the members of the type-----or even dynamically invoke one of the members (the so-called "dynamic invocation member", which means deciding which member to call when the
program is running), depending on the circumstances. If the two seemingly identical types differ in their order of membership, they can result in unexpected results.
To avoid these problems, the designer of C # ultimately decides that two different types are generated if the order of the attributes is different. Another feature added to
II, collection initializers
c#3.0 is the collection initializer.
using a collection initializer, a programmer can take a similar approach to an array of declarations and construct the collection with an initial set of members during instantiation of a collection.
If you do not have a collection initializer, you can explicitly add members to the collection only after the collection has been instantiated.
Class program { static void main (String[] args) { list sevenworldblunders = new list (
); sevenworldblunders = new list () { " Wealth without work ", " Pleasure without conscience ",
"Knowledge without character", };
print (sevenworldblunders);    &NBSP} private static void print (IEnumerable Items) {     &NBsp; foreach (T item in items) {
console.writeline (item); }  }}
This syntax is not only similar to the syntax of array initialization, but also similar to object initializer syntax.
To successfully compile a collection initializer, several basic conditions need to be met. Ideally, the collection type should implement the
System.Collections.Generic.ICollection interface.
Or there is one or more add methods on the type that implements the IEnumerable.
The collection initializer is not available for anonymous types. There are several ways to solve this problem. Fever
What is the use of the class to become a set: ienumberable
By definition,. NET is essentially a class that implements the IEnumerable at least (technically, it should be a non-generic type
Ienumberable.
To support traversal of a set, the minimum requirement is to implement the method defined by Ienumberable.
Note: The runtime has no idea what the foreach statement is.
1, foreach and array
int[] arr = new[] {1, 2, 3, 4, 5};
foreach (int item in arr)
{
Console.WriteLine (item);
}
Based on this code, the C # compiler uses CIL to create an equivalent for loop.
foreach in this case relies on the support of the length attribute and the array index operator [].
2, foreach and IEnumerable
Not all types of collections contain a known number of elements.
In addition, many collection classes, including stack , Queue and Dictionary , it is not supported to get elements by index.
Therefore, a more conventional way is needed to traverse the collection of elements. The iterator (iterator) pattern provides this capability.
As long as you can determine the first element, the next element, and the last element, you do not need to know the total number of elements in advance, nor do you need to follow the index to get the elements.
System.Collections.Generic.IEnumerator and the non-generic System.Collections.Generic.IEnumerator interface design goal is to allow
Iterator mode to traverse the collection of elements while discarding the use: the length---index (length---index) mode used above.
IEnumerator Derived from IEnumerator, which contains 3 members.
The first member is BOOL MoveNext ().
The second member is read-only property current, which returns the present element.
With these two members, you can iterate through the collection with just one while loop.
But there are two important implementation details: Interleaving and error handling
2.1 State sharing
If there are two loops interleaved through the same set (one foreach nested another),
The collection must maintain a status indicator of the current element to ensure that the next element is positioned correctly when MoveNext () is invoked.
The problem now is that staggered loops may interfere with each other (the same problem occurs if the loop is executed by multiple threads).
To solve this problem, the collection class does not directly support IEnumerator and IEnumerator interfaces.
There is also a second interface, which is named IEnumerable , its only method is GetEnumerator ().
The function of this method is to return support IEnumerator An object. Here, the state is not maintained by the collection class.
Instead, it is supported by a different class (usually a nested class for access to the collection interior) to support the IEnumerator Interface
and is responsible for maintaining the loop traversal state.
The enumerator is the equivalent of a "cursor" or "bookmark."
You can have multiple bookmarks, and moving each bookmark allows you to traverse the collection independently of other bookmarks.
2.2 Cleanup Status
Since it was realized by the IEnumerator interface, so it is sometimes necessary to clean the state after exiting the loop.
For this IEnumerator Interface is derived from IDisposable. The enumerator that implements IEnumerator does not necessarily implement IDisposable.
However, if IDisposable is implemented, the Dispose () method is called.
A foreach without IEnumerable:
Technically, the compiler is not required to support IEnumerator in order to use foreach to iterate over a data type. /ienumerator.
Instead, the compiler takes a concept called "Duck typing."
Duck Typing.
3, do not modify the collection
3rd chapter in the Foreach loop the compiler prohibits assigning a foreach variable identifier.
If the collection was modified during the Foreach loop, the re-access enumerator raises system. The
InvalidOperationException type exception, which indicates that the collection has changed since the enumerator was instantiated.
Iterators can also be affected.
Four, standard query operators
If the method defined by System.Object is excluded, then any type that implements IEnumerable has only one side method,
i.e. GetEnumerator ().
In fact, there are more than 50 methods available for any type after implementing IEnumerable . The
does not include overloaded versions. The
only requires an explicit implementation of the GetEnumerator () method in the interface.
Other additional features are provided by the c#3.0 extension method.
All methods are defined in the System.Linq.Enumerable class.
So, in order to use these methods, simply add the following statement:
using System.Linq; Each method on the
IEnumerable is a standard query operator (standard query operator).
It provides the ability to query the collection in which it operates.
Example class:
Class program { static void main (String[] args) { ienumerable patents = patentdata.patents
;
print (patents);
console.writeline ();
IEnumerable inventors = PatentData.Inventors;
print (inventors);
console.readline ();    &NBSP} public static void print (IEnumerable Items) { foreach (t item In items) {
console.writeline (item); &nBSP;   &NBSP} //Patent class Public class patent { public string title { get; set; } public string yearofpublication { get; set; } public string applicationnumber { get; set; }
public long[] inventorids { get; set; } public override string tostring () { Return string.
Format ("{0} ({1})", title, yearofpublication); }  &NBSP} //inventor class public class inventor { public long Id { get; set; } public string Name { get; set; } public string City { get; set; } public string State { get; set; } public string Country { get; set; } public override string ToString () { return string.
Format ("{0} ({1},{2})", name, city, state); &nbsP;   &NBSP}  } //actual data Public static class patentdata { public static readonly inventor[] inventors = new inventor[] { new inventor () { name= "Benjamin Franklin ", city=" Philadelphia ", state= "PA", country= "USA", id=1
}, new inventor () { name= "Orville wright ", city=" Kitty hawk ", State= "NC", country= "USA", id=2 new inventor () { name= "Wilbur Wright", City= "Kitty hawk ", State= "NC", country= "USA", id=3 new inventor () { name= "Samuel Morse", City= "New york ", State= "NY", couNtry= "USA", id=4  , new inventor () { name= "George stephenson", City= "Wylam", state= "
Northumberland ", country=" UK ", id=5 new inventor () { name= "John Michaelis", City= "Chicago", State= "IL", country= "USA", id=6 }, &Nbsp; new inventor () { name= "Mary phelps jacob", City= "New York", state= "NY", Country= " USA ", id=7 },
}; public static readonly patent[] patents = new patent[] { New patent () { title= "Bifocals", yearofpublication= "1784", inventorids=new long[]{1}       &NBSP}, new patent () { title= "Phonograph", yearofpublication= "1877", inventorids=new long[]{1}      &NBSP}, New patent () { title= "Kinetoscope", yearofpublication= "1888", inventorids=new long[]{1}      &NBSP}, New patent() { title= " Electrical telegraph ", yearofpublication=" 1837 ",        INVENTORIDS=NEW LONG[]{4}      &NBSP}, New patent () { title= "Flying machine", yearofpublication= "1903", inventorids=new long[]{2,3}       &NBSP}, new patent () { title="Steam locomotive", yearofpublication= "1815",       INVENTORIDS=NEW LONG[]{5} }, new patent () { title= "Droplet deposition apparatus", yearofpublication= "1989",            INVENTORIDS=NEW LONG[]{6}          &NBSP}, new patent () { title= "Backless brassiere", yearofpublication= "1914", inventorids=new long[]{7}
       &NBSP}, };    &NBSP}}
The form parameters of the lambda expression below are of the same type as the element type in the collection.
1. Use where () to filter
To filter out some data from the collection, you need to provide a filter method that returns TRUE or false, indicating
Whether a particular element should be included in it.
The delegate expression that gets an argument and returns a Boolean value is called a predicate.
IEnumerable patents = patentdata.patents;
patents = patents. Where (
patent => patent). Yearofpublication.startswith ("a")
);
Print (patents);
Note: The code assigns the output of the Where () to IEnumerable .
IEnumerable . The Where () output is a new collection of IEnumerable . The above code returns the IEnumerable . The expression arguments for the
Where () method are not necessarily evaluated at assignment time. This applies to many standard query operators.
in the case where (), the expression is passed to the collection, "saved" but not executed immediately.
Instead, the expression is really evaluated only when you need to traverse the items in the collection.
should interpret the where () method as simply describing what should appear in the collection, and it does not involve more practical work.
2, using Select () to Project
due to IEnumerable . The Where () outputs a new
IEnumerable collection, so you can invoke another standard query operator
using SELECT () on the basis of this collection.
IEnumerable patents = patentdata.patents;
IEnumerable patents1800 = patents. Where (
patent => patent). Yearofpublication.startswith ("a")
);
IEnumerable items = patents1800. Select (item => item. ToString ());
Print (patents);
Print (items);
In this code, a new IEnumerable collection is created . Although a select () call was added, it was not
Cause any change in output.
Obviously, one conversion occurs for each data item: The patent type from the original collection is converted to a string of the Items collection.
IEnumerable filelist = Directory.GetFiles ("d:\\");
IEnumerable files = filelist. Select (File => new FileInfo (file));
Print (files);
Note: The form parameters of the lambda expression above are of the same type as the element type in the collection.
Anonymous Type:
IEnumerable filelist = Directory.GetFiles ("d:\\");
var items = filelist. Select (file =>
{
FileInfo FileInfo = new FileInfo (file);
return new {FileName = Fileinfo.name, Size = fileinfo.length};
Print (items);
Filters a collection in the vertical direction (reducing the number of elements in the collection project) using the WHERE () standard query operator.
Now using the Select () standard query operator, you can also reduce the size of the collection in the horizontal direction (reducing the number of columns) or make a thorough conversion of the data.
Using the Where () and select (), a subset of the original set can be obtained to meet the requirements of the current algorithm.
Parallel operation of LINQ query:
The modification program supports multithreading.
IEnumerable filelist = Directory.GetFiles ("d:\\");
var items = filelist. AsParallel (). Select (file =>
{
FileInfo FileInfo = new FileInfo (file);
return new {FileName = Fileinfo.name, Size = fileinfo.length};
Print (items);
The changes that occur in the code make it easy for parallel support.
The only thing to do is to use the standard query operator AsParallel () introduced in the. NET Framework 4.
This is a member of the static class System.Linq.ParallelEnumerable.
Using this simple extension method, the runtime iterates through the data items in the FileList and returns the resulting object, both of which occur in parallel.
3. Count the Elements with count ().
Use COUNT () to count the number of all elements, or to get a predicate as a parameter that counts only the data items that are specified by the predicate expression.
ienumerable patents = patentdata.patents; Console.WriteLine ("Patent count:{0}", patents.
Count ()); Console.WriteLine ("Patent count in 1800s:{0}", patents. Count ( patent => patent. Yearofpublication.startswith ("a") );
&NBSP
Although the count () statement is simple to write, but IEnumerable has not changed, the code that is actually executing still iterates through all the items in the collection.
If the collection provides a Count property directly, you should prefer this property instead of the LINQ count () method.
Fortunately, ICollection contains the Count property, so if a collection supports ICollection , the Count () method is called on it to transform the collection
and call count directly. Then, if ICollection is not supported, Enumerable.count () enumerates all the items in the collection, rather than the Count mechanism built within the call
.
If the purpose of the count is only to see if the count is greater than 0, then the preferred option is to use the any () operator
if (patents). Any ())
{ }
. The
any () attempts to traverse only one item in the collection and returns True if successful. It does not traverse the entire sequence.
4, when you postpone the execution of
using LINQ, an important concept is deferred execution.
ienumerable patents = patentdata.patents;
bool result; Patents = patents. Where (patent => { if ( Result = patent. Yearofpublication.startswith ("a") { console.writeline ("WHERE STARTSWITH 18 :"
+ patent); } return
Result
});
Console.WriteLine ("1. patents prior to the 1900s are:");
foreach (patent patent in patents) {} console.writeline (); Console.WriteLine ("2. a second listing of patents prior to the
1900s: "); Console.WriteLine (" there are {0} patents prior to 1900. ", patents.
Count ());
Console.WriteLine (); Console.WriteLine ("3. a third listing of patents prior to the
1900s: "); Patents = patents.
ToArray ();
Console.Write (" There are "); Console.WriteLine ("{0} patents prior to 1900."), patents. Count ());
Code output:
1. Patents prior to the 1900s are:
Where startswith:P honograph (1877)
Where startswith 18:kinetoscope (1888)
Where startswith 18:electrical Telegraph (1837)
Where StartsWith 18:steam locomotive (1815)
2. A second listing of patents prior to the 1900s:
Where startswith:P honograph (1877)
Where startswith 18:kinetoscope (1888)
Where startswith 18:electrical Telegraph (1837)
Where StartsWith 18:steam locomotive (1815)
There are 4 patents prior to 1900.
3. A third listing of patents prior to the 1900s:
Where startswith:P honograph (1877)
Where startswith 18:kinetoscope (1888)
Where startswith 18:electrical Telegraph (1837)
Where StartsWith 18:steam locomotive (1815)
There are 4 patents prior to 1900.
Note that Console.WriteLine ("1"). Patents prior ... "); is performed before a lambda expression.
This is a very important feature.
In general, any predicate should only do one thing: evaluate a condition. It should not have any "side effects" (such as printing to the console in this case).
To understand what's going on behind this, remember that a lambda expression is a delegate that can be passed somewhere else-----is a reference to a method (method pointer).
In the context of LINQ and standard query operators, each lambda expression forms part of the overall query to be executed.
When declared, they are not executed. The lambda expression does not execute unless the lambda expression is invoked, causing the code to start executing.
The 3 calls in the above code trigger the execution of the lambda expression, which is triggered implicitly each time.
If the Lamba expression executes at a higher cost (such as calling a database), it is important to optimize the code to minimize
The execution of a lambda expression.
First: The execution of a lambda expression is triggered within a foreach loop. The Foreach loop is decomposed into a MoveNext () call, and each call creates a
Each item in the original collection executes a lambda expression. During a loop iteration, run time invokes a lambda expression for each item to determine whether the item satisfies the predicate.
Second: the count () function of the enumerable is invoked, and the lambda expression is again triggered for each item. This is easily overlooked because the standard query operator is not used to query
Collection, the Count property is very common.
Finally, calling ToArray () (or ToList (), todictionary (), or tolookup ()) triggers a lambda expression for each item.
It is quite useful to use these toxxx methods to transform a collection. This returns a collection that the standard query operator has already processed.
This returns a collection that the standard query operator has already processed. In the above code, converting to an array means that the last Consloe.writeline () statement calls the
Length, the underlying object that patents points to is actually an array (it clearly implements the IEnumerable ), so the length of the call is implemented by System.Array,
Instead of being implemented by System.Linq.Enumerable.
Therefore, after a toxxx method is converted to a collection type, it is generally safe to manipulate the collection (unless another standard query operator is invoked). But be aware that this will
Causes the entire result set to be loaded into memory (which can reside in a database or file before that). In addition, the ToXxx method creates a "snapshot" of the underlying data to ensure that
When you requery the results of the ToXxx method, new results are not returned.
Developers are wary of triggering standard query operators unknowingly.
A Query object represents a query, not a result.
When you request a result from a query, the entire query executes because the query object is not sure of the result and the result of the previous execution is not the same.
Note: To avoid this repetitive execution, after a query has been executed, it is necessary to cache the array it gets.
In general, if the "snapshot of a collection in memory" is what you want, the best thing to do is to assign a query expression to a cached collection to avoid unnecessary iterations.
Order diagram: To be replicated p426 433 is in contrast to the actual code.
5. Use order by () and ThenBy () to sort
To sort, which involves a call to the System.Linq.Enumerable by ().
ienumerable items = null;
patent[] patents = patentdata.patents; Items = patents. by (Patent => patent). yearofpublication) ThenBy (patent => patent.
Title);
Print (items);
Console.WriteLine (); Items = patents. OrderByDescending (patent => patent. yearofpublication) ThenByDescending (patent => patent.
Title); Print (items);
By order () gets a lambda expression that identifies the key to be sorted accordingly.
Subsequent sorting requires the use of ThenBy ()
Order BY () returns a Iorderedenumerable interface, not a IEnumerable . In addition,
Iorderedenumerable is derived from IEnumerable , so you can use all the standard query operators for the return value of order by ().
However, if you repeatedly invoke by (), the Last by () is revoked.
to specify additional sorting criteria, you should use ThenBy (). defined on the System.Linq.Extensions.Enumerable.
In summary, use order order (), and then execute 0 or more calls to ThenBy () to provide an extra sort column.
Sorting, there are two important issues:
First, the sort is actually started when you start to access members of the collection, at which point the entire query is processed.
Obviously, you cannot sort unless you take all the items that you want to sort. If you do not get all the items, you cannot determine whether you have obtained the
first item. The sort is manipulated to begin when the member is first accessed.
In fact, the previous Keyselector lambda expression (the expression in order by) is called again when the subsequent data sort call is performed.
6, using join () to perform an inner join
on the client side, the relationship between objects and objects is generally established.
However, data that is loaded from a non-object store is generally not the case.
Instead, the data needs to be joined together so that you can switch from one object type to the next in a way that fits the data.
Class program { static void main (String[] args) { Department[] departments =
corporatedata.departments;
Employee[] employees = CorporateData.Employees; var items = employees. Join ( departments,//associated with data employee => employee. Reference properties for departmentid,//joins department => department. Reference properties for id,//joins (employee, Department) => new //returned data { &nbsP; employee. Id, employee. Name, employee. Title,
Department = department });
print (items);
console.readline ();    &NBSP} public static void print (IEnumerable Items) { foreach (t item In items) { &nbsP; console.writeline (item);        &NBSP} //Department class public class department { public long id { get; set; } public string name { get; set; } public override string tostring () { return string.
Format ("{0}", name);        &NBSP    &NBSP} //Employee Class public class employee { public int id { get; set;&nbSP;}
public string name { get; set; } public string Title { get; set; } public int DepartmentId { get; set; &NBSP} public override string tostring () { return string.
Format ("{0} ({1})", name, title);        &NBSP}  } //actual data public static class corporatedata { public static readonly Department[] Departments = new department[] { new department () { name= "Corporate", Id=0    &NBSP}, new Department () { name= "Corporate", Id=1          &NBSP}, new department () { Name= "Engineering", id=2            &NBSP}, new department () { name= "Information technology", id=3   &NBSP}, new Department () { name=, Id=4         &NBSP}, new department () {   &NBsp; name= "Marketing", Id=5          &NBSP},
}; public static readonly Employee[] employees = new employee[] { new employee () { name= "Mark Michaelis ", Title= "Chief computer nerd", departmentid=0 },   &NBsp; new employee () { name= "Michael stokesbary", title= "Senior computer wizard", departmentid=2         &NBSP},
new employee () { name= "Brian jones ", Title= "EnterpRise integration guru ", departmentid=2 }, new employee () { name= "Jewel floch", title= "Bookkeeper extraordinaire", departmentid=1           &NBSP}, new employee () { name= "Robert Stokesbary ", Title= "Expert mainframe engineer", departmentid=3 &NBSP}, new employee () { name= "Paul r.bramsman", title= "Programmer Extraordinaire" , departmentid= 2          &NBSP}, new employee () { name= " Thomas heavey ", title= "Software architect", departmentid=2 }, new employee () { name= "John michaelis", title= "Inventor", departmentid=4
     &NBSP}, };    &NBSP}}
Output:
{Id = 0, Name = Mark Michaelis, Title = Chief Computer Nerd, Department = Corpo
Rate}
{Id = 0, Name = Michael stokesbary, Title = Senior Computer Wizard, Department
= Engineering}
{Id = 0, Name = Brian Jones, Title = Enterprise integration Guru, Department =
Engineering}
{Id = 0, Name = Jewel Floch, Title = bookkeeper extraordinaire, Department = Co
Rporate}
{Id = 0, Name = Robert stokesbary, Title = Expert Mainframe Engineer, departmen
t = Information Technology}
{Id = 0, Name = Paul R.bramsman, Title = programmer extraordinaire, Department
= Engineering}
{Id = 0, Name = Thomas Heavey, Title = Software Architect, Department = Enginee
Ring}
{Id = 0, Name = John Michaelis, Title = inventor, Department = the
The first parameter of Join () is inner, which specifies the set of targets to be connected to.
The next two parameters are lambda expressions that specify how two collections are joined.
The last parameter is also a lambda expression that describes how to select or group the result items.
Note: The above uses an array, which shows that the interface is implemented IEnumerable
7, the use of groupby grouped results
Groups objects that have similar characteristics.
For example: For employee data, you can group employees by department, region, position, etc.
I
Enumerable employees = Corporatedata.employees;
IEnumerable departments = corporatedata.departments;
ienumerable<igrouping> groupedemployees =
employees. GroupBy (Employee => employee. DepartmentID);
foreach (igrouping employeegroup in groupedemployees)
{
Console.WriteLine ();
foreach (Employee employee in Employeegroup)
{
Console.WriteLine ("T" +employee);
}
Console.WriteLine ("\ t Count:" +employeegroup.count ());
}
Output:
Mark Michaelis (Chief Computer Nerd)
Count:1
Michael stokesbary (Senior Computer Wizard)
Brian Jones (Enterprise integration Guru)
Paul R.bramsman (programmer extraordinaire)
Thomas Heavey (Software Architect)
Count:4
Jewel Floch (bookkeeper extraordinaire)
Count:1
Robert stokesbary (Expert Mainframe Engineer)
Count:1
John Michaelis (inventor)
Count:1
GroupBy () returns the IGrouping type that has a property representing the data item for the
The key to use as the group basis. However, it does not prepare a property for the data items in the group.
Conversely, since igrouping is derived from IEnumerable , you can use a foreach
Statement to enumerate the items in a group, or to aggregate the data into an imaging item (Employeegroup.count ()).
8, using GroupJoin (0) to achieve a one-to-many relationship
Create a list of employees, and explicitly belong to the department, but not in each employee data added,
Instead of creating a record of anonymous types for each department-employee relationship, you display a collection of all the members of a department subordinate.
ienumerable employees = corporatedata.employees;
ienumerable departments = corporatedata.departments; Var items = departments. GroupJoin ( employees,//associated Object array department => Department. id,//the associated key employee => employee.
departmentid,//associated Key (department, departmentemployees) => new//returned data { department. Id, department. Name, employees = departmentemployees
}); foreach (Var item in items) { console.writeline ("department: {0}", item.)
Name+ ":"); foreach (Employee employee in item. Employees) { console.writeline ("T" +employee); &NBSP;&NBSP;&NBSP;&NBSP}}
Output:
Department: Corporate:
Mark Michaelis (Chief Computer Nerd)
Department: Corporate:
Jewel Floch (bookkeeper extraordinaire)
Department: Engineering:
Michael stokesbary (Senior Computer Wizard)
Brian Jones (Enterprise integration Guru)
Paul R.bramsman (programmer extraordinaire)
Thomas Heavey (Software Architect)
Department: Information Technology:
Robert stokesbary (Expert Mainframe Engineer)
Department::
John Michaelis (inventor)
Department: Marketing:
Unlike join, there is nothing in SQL that is equivalent to GroupJoin, because the data returned by SQL is based on records,
Rather than hierarchically structured.
Note: Use GroupJoin () with SelectMany () external connection
9, call SelectMany ()
Handling collections constructed by collections
SelectMany will spread over each item identified by the lambda expression and place each item in a new collection.
The new collection consolidates all the items in the child collection, so instead of returning two sets as select (), it is
Each array is selected and the items are consolidated into a single collection.
The select is to iterate over the set of IEnumerable to traverse each time, return a T,
After merging, return directly to a IEnumerable,
and SelectMany the original collection IEnumerable each element to traverse again, each return a IEnumerable,
After merging these IEnumerable "T", the whole returns to a IEnumerable.
So we can say that in general, SelectMany is used to return a ienumerable> "nested" return (the IEnumerable that merges each IEnumerable and returns a whole). So it's often possible to save code when nesting,
string[] Text = {"A B", "C D", "E F"};
var items = text. Select (
item => item. Split (")"
);
foreach (string[] strs in items)
{
foreach (string str in STRs)
{
Console.WriteLine ("T" +s TR);
}
//replace SelectMany
string[] Text = {"A B", "C D", "E F"};
var items = text. SelectMany (
item => item. Split (")"
);
foreach (var item in items)
{
Console.WriteLine ("\ T" + Item);
}
Output:
A
B
C
D
E
F
10. More standard query operators
The simpler APIs provided by enumerable do not require lambda expressions.
System.Linq.Enumerable provides a series of aggregate functions that can enumerate sets to compute a result.
such as Count ().
OfType ()
Union ()
Concat ()
Intersect ()
Distinct ()
Sequenceequals ()
Reverse ()
The provided aggregate function
Count ()
Average ()
Sum ()
Max ()
Min ()
Advanced topic: iquerable The queryable extension
There's an interface almost and IEnumerable Exactly the same, this is IQueryable 。
Because IQueryable It's from IEnumerable. derived, so it has all members of the IEnumerable ---
but only those that are directly declared, such as GetEnumerator (). Extension methods are not inherited.
So there is no extension method for enumerable.
Then, it has a similar extension class, called System.Linq.Queryable.
Iquerable makes the custom LINQ provider a feature.
The role of LINQ provider is to break an expression into components.
Once decomposed, the expression can be converted to another language and can be serialized for remote execution,
can be injected through an asynchronous execution pattern.
Simply put, the LINQ provider introduces an "explanation" mechanism in a standard collection API.
with this almost unlimited functionality, the behavior associated with queries and collections can be "injected".
If you take advantage of LINQ Provider, you can convert a query expression from C # to SQL and execute on a remote database.
This way, the C # program can continue to use the object-oriented language that he is familiar with, leaving the conversion to SQL to the underlying LINQ
Provider.
Caution: Postpone execution and unknowingly invoke any costly,
potentially deferred, operation.
C # about standard query operators tutorial
definition
Ienu Each method on the merable is a standard query operator (Standard query Operator). It provides the ability to query a collection.
Note that there is a difference between the query operator and the query expression.
Here is a simple example of
a plain sample show how to use.
using system; using system.collections.generic; using System.Linq;
using system.text; namespace linqsample01 { class Program { public class Student { public string first { get; set; } public string Last { get; set; } public int ID { get; set; } public list scores; } // Create a data source by using a collection initializer. static List
students = new list { new student {first= "Svetlana", last= "Omelchenko", id=111, scores= new list {97, 92, 81, 60}}, new student {first= " Claire ", last=" O ' Donnell ", id=112, scores= new list {75, 84, 91, 39}}, new Student {first= "Sven", last= "Mortensen", id=113, scores= new list {88, 94, 65, 91}}, new Student {first= "Cesar", last= "Garcia", id=114, scores= new list {97, 89, 85, 82}}, new student {first= "Debra", last= "Garcia", id=115, scores= new list {35, 72, 91, 70}}, new student {first= "Fadi", last= "
Fakhouri ", id=116, scores= new list {99, 86, 90, 94}}, new student {first= "Hanying", last= "Feng", id=117, scores= new list {93, 92, 80, 87}}, new student {first= "Hugo", last= "Garcia", id=118, scores= new list {92, 90, 83, 78}}, new student {first= "Lance", last= "Tucker", id=119, scores= new list {68, 79, 88 , 92}}, new student {first= "Terry", last= "Adams", id=120, scores= new list { 99, 82, 81, 79}}, New student {first= "Eugene", last= "Zabokritski", id=121, scores= new list&nbsP {96, 85, 91, 60}}, new student {first= "Michael", last= "Tucker", id=122, scores= new List {94, 92, 91, 91} } }; static void main ( String[] args) { ienumerable studentquery = students. Where ( student => student. scores[0] > 90 ); foreach (student item in
Studentquery) { Console.WriteLine ("Name: {0} : {1}", item. Last, item.
Scores[0]); } console.readkey (); } } }
a knowledge point about the LINQ query operator.
-About IEnumerable
The essence of the collection in. NET is a class, and the key to this class is the implementation of the IEnumerable The interface. To implement traversal of a collection
The key is to achieve IEnumerable The method specified in.
IEnumerator and IEnumerable Iterator traversal.
This is similar to the C + + STL iterator idea, for a set, if we know the number of its specific elements, we can use
for (int i = 0; i < Array.Length i++) the (Length-index) way to implement traversal, but for a collection that does not know the specific element,
The more appropriate way is to iterate from the first to the last. The goal of the IEnumerator implementation is to allow traversal by using an iterator approach.
- Collection Initializers
Create a data source by using a collection initializer.
Static List Students = new List
{
New Student {first= "Svetlana", last= "Omelchenko", id=111, scores= new List {97, 92, 81, 60}},
New Student {first= "Claire", last= "O ' Donnell", id=112, scores= new List {75, 84, 91, 39}},
... ...
};
This code initializes a collection List with an initialization array , but the collection must normally be instantiated to add a member.
In fact, we use C # 3.0, a new feature collection initializer.
In order to compile successfully, the collection initializer is ideally set to support System.Collections.Generic.ICollection interface, so that you can guarantee
Collection supports the ADD () method.
Not all collections support the collection initializer for two reasons:
1 not all collections are implemented ICollection interface, in other words, this interface is not useful for each collection.
2 because the method name is matched, for example, a collection initializer supports the new Datastore () {A, {b,c}}, which means the Add () method
To support both interfaces add (a) and add (b, c), interface diversification can be convenient for the program, but sometimes also a burden.
- Linq Functions
where () filter
IEnumerable studentquery = students. Where (
student = > Student. Scores[0] >
);
Note that the expression arguments for the: where () method are not necessarily evaluated when they are assigned, and are evaluated only when the collection items need to be traversed. The
Select () Project
SELECT clause can specify the type of value that will be generated when the query is executed
; In the simplest case, the SELECT clause specifies only the range variable. This causes the returned sequence to contain elements of the same type as the data source.
Use Select for result conversions:
Convert query results to XML format (http://msdn.microsoft.com/zh-cn/library/ bb397914 (v=vs.90). aspx)
class xmltransform { static void main () { // Create the data source by using a collection initializer.
list students = new list () { new student {first= "Svetlana", Last= "Omelchenko ", id=111, scores = new list{97, 92, 81, 60}}, new student {first= "Claire", last= "O ' Donnell", ID=112, Scores = new List{75, 84, 91, 39}}, new student {first= "Sven", last= "Mortensen", id=113, scores = new list{88, 94, 65, 91}}, }; // Create the query. var studentstoxml = new xelement ("Root", from student in students let x = string.format ("{0},{1},{2},{3}", student.) scores[0], student. Scores[1], student. Scores[2], student. SCORES[3]) select new xelement ("Student", new xelement ("A", student. A), &Nbsp; new xelement ("Last", student. Last), new xelement ("Scores", x)
) // end "Student" ); // end "Root" // Execute the query. Console.WriteLine (studentstoxml); // Keep the console open in debug mode. console.writeline ("Press any Key to exit. "); console.readkey (); } }
Count () counting
The count operation used to get the number of elements on the collection. function is very simple, use to be careful.
There are two places to print count arrays in the instance's code.
Console.WriteLine ("ICollection Count:", students.) Count ());
Console.WriteLine ("IEnumerable Count:", Studentquery.count ());
They are similar in that they look at how many elements there are, but the difference is that ICollection has the Count attribute, but IEnumerable
Will enumerate through the entire collection.
If you just want to determine if the count is greater than 0---> if (IEnumerable) . Count () > 0) {...}
Then replace it, if (IEnumerable . Any ()) {...}, you will only attempt to traverse one of the elements.
-Deferred execution of---query repeatedly
This is a very important concept, first look at a piece of code, the code is very simple, to illustrate the problem is that in some cases when we
When we do not want to traverse the entire collection, we iterate over the entire collection in some unexpected places, due to the delay of IEnumerable.
using system; using system.collections.generic; using System.Linq;
using system.text; namespace delayexecute { class Program { static void main (String[] args) { // Specify the data source. int[] scores = new int[] { 97, 92, 81, 60 }; bool result = false; iEnumerable scorequery = scores. Where ( score => { result = false; if (score > 80) { result = true; &Nbsp; console.writeline (" Score = {0} ", score); } return result; &NBSP;&NBSP;&NBSP}); console.writeline ("==============================================="); console.writeline ("1") Invoke empty foreeach, it will execute "); foreach (int i in scorequery) { } Console.WriteLine ("==============================================="); console.writeline ("2) Invoke IEnumerable Count, it will execute "); scorequery.count ();
console.writeline ("==============================================="); console.writeline ("3) Invoke ienumerable toarrAy, it will execute "); scorequery = scorequery.toarray (); console.readkey (); } } }
1 The essence of Foreach:foreach is to invoke the MoveNext (), which is the switch that triggers the traversal.
2 count: As discussed earlier, the IEnumerable count is not a property, but a function.
3 toarray:toxxx is a good thing to turn a collection into an object that can be safely manipulated, but it also triggers traversal and loads the results into memory.
The following sequence diagram is a simple summary of deferred execution.
Some of the other query functions
These functions are similar to those used in SQL, and can be used to help understand the idea of SQL.
by () and ThenBy ()
using system; using system.collections.generic; using System.Linq;
using system.text; namespace testorderapi { class Program { public class Student { public string first { get; set; } public string Last { get; set; } public int ID { get; set; } public list scores; } // Create a data source by using a collection initializer. static List
students = new list { new student {first= "Svetlana", last= "omelchenko ", id=111, scores= new list {97, 92, 81, 60}}, new Student {first= "claire ", last= "O ' donnell ", ID=112, scores= new list {75, 84, 91, 39}}, new student {first= "sven ", last= " mortensen ", id=113, scores= new list {88, 94, 65, 91}}, new student {first= " cesar ", last=" garcia ", ID=114, Scores= new List {97, 89, 85, 82}}, new student {first= "debra ", last= "garcia ", id=115, scores= new list {35 , 72, 91, 70}}, New student {first= "fadi ", last= "Fakhouri ", &NBSP;ID=116,&NBSP;SCores= new list {99, 86, 90, 94}}, new student {first= "hanying ", Last= "feng ", id=117, scores= new list {93, 92, 80, 87}}, new Student {first= "hugo ", last= "Garcia
", id=118, scores= new list {92, 90, 83, 78}}, new student {first= "Lance ", last=" tucker ", id=119, scores= new List {68, 79, 88, 92}}, &Nbsp;new student {first= "terry ", last= "Adams ", id=120, scores= new list {99, 82, 81, 79}}, new student {first= " eugene ", last=" Zabokritski ", id=121, scores= new list {96, 85, 91, 60}}, new student {first= "michael ", last= "Tucker ", id=122, scores= new list {94, 92, 91, 91} } }; static void main (String[] args) { IEnumerable Studentquery = students. by ( student => student. Scores[0]). ThenBy (student => student. SCORES[1]); foreach (student item in studentquery) { console.writeline ("Name: {0} : {1}", {2} ", item. Last, item. Scores[0], item.
SCORES[1]); } console.readkey (); } } }
The
join ()
is used to connect two collections with a keyword. Here is the Teamid
using system; using system.collections.generic; using System.Linq; using system.text; namespace testjoinapi { class Program { public class Student { public string First { get; set; } public string Last { get; set; } public int ID { get; set; } public list scores; public int teamid { get; set; } }
public class Team { public int TeamID { get; set; } public string TeamName { get; set; } } // Create a data source by using a collection initializer. static List students = new list { new student {first= "Svetlana", Last = "Omelchenko", id=111, scores= new list {97, 92, 81, 60}, teamid= 0}, new student {first= "Claire", last= "O ' Donnell", id=112, scores= new list {75, 84, 91, 39}, TeamID=1}, new student {first= "Sven", last= "Mortensen", id=113, scores= new list {88, 94, 65, 91}, teamid=0}, new student {first= "Cesar", Last= "Garcia," &N.bsp;id=114, scores= new list {97, 89, 85, 82}, teamid=1}, new student {first= "Debra", last= "Garcia", id=115, scores= new list {35, 72, 91, 70}, TeamID=0}, new student {first= "Fadi", last= "Fakhouri", id=116, scores= new List {99, 86, 90, 94}, TeamID=1}, new student {first= "Hanying", Last= "Feng", ID=117, Scores= new List {93, 92, 80, 87}, TeamID=0}, new student {first= "Hugo", last= "Garcia", id=118, scores= new list {92, 90, 83, 78}, teamid=1}, new student {first= " Lance ", last=" Tucker ", id=119, scores= new list {68, 79, 88, 92}, TeamID=0}, new student {first= "Terry", last= "Adams", id=120, scores= new List {99, 82, 81, 79}, TeamID=1}, new student {first= "Eugene", last= " Zabokritski ", id=121, scores= new list {96, 85, 91, 60}, teamid=0 }, new student {first= " Michael ", lasT= "Tucker", id=122, scores= new list {94, 92, 91, 91}, teamid=1 } }; // create a data source by using a collection initializer. static list
teams = new List { new team {teamid = 0, teamname= "Team a"}, new team {teamid = 1, teamname= "Team b"}, }; Static void&nbsP Main (String[] args) { var items = students. Join (teams, student => student. teamid, // the key one for join team => team. Teamid, // the key two for join (Student, team) => new // the new collection items { team. teamid, team. teamname, student.ID, student. first, &NBSP;&NBSP;&NBSP;&NBSP;&NBSP}). by (Team => team). TEAMID); foreach (var item in items) { console.writeline ("Team {0} : {1} {2}", item. Teamname, item.id, item. (a); }
console.readkey (); } } }
The
GroupBy ()
is used to group objects that have similar characteristics.
using system; using system.collections.generic; using System.Linq;
using system.text; namespace testgroupbyapi { class Program { public class Student { public string first { get; set; } public string Last { get; set; } public int ID { get; set; } public List scores; public int TeamID { get; set; } } // Create a data source by using a collection initializer. static List students = new List { new student {first= "Svetlana", last= "Omelchenko", id=111, scores= new list {97, 92, 81, 60}, TeamID=0}, new student {first= "Claire", last= "O ' Donnell", ID=112, scores= new List {75, 84, 91, 39}, TeamID=1}, new student {first= "Sven", last= " Mortensen ", id=113, scores= new list {88, 94, 65, 91}, teamid=0}, new student {first= " Cesar ", last=" Garcia ", id=114, scores= new list {97, 89, 85, 82}, TeamID=1}, new student {first= "Debra", last= "Garcia", id=115, scores= new List {35, 72, 91, 70}, TeamID=0}, new student {first= "Fadi", Last= "Fakhouri", id=116, scores= new list {99, 86, 90, 94}, teamid=1}, new student {first= "Hanying", last= "Feng", id=117, scores= new list {93, 92, 80, 87}, teamid=0}, new Student {first= "Hugo", last= "Garcia", id=118, scores= new list { 92, 90, 83, 78}, teamid=1}, new student {first= "Lance", last= "Tucker", ID=119, Scores= new List {68, 79, 88, 92}, TeamID=0}, new student {first= "Terry", last= "Adams", id=120, scores= new list {99, 82, 81, 79}, teamid=1}, new student {first= "Eugene", last= "Zabokritski", id=121, scores= new list {96, 85, 91, 60}, teamid=0}, new Student {first= "Michael", last= "Tucker", id=122, scores= new list {94 , 92, 91, 91}, teamid=1 } }; static void main (string[) args) { IEnumerable<IGrouping> StudentGroup = Students. GroupBY ( (student) => student. Teamid); foreach (igrouping group in studentgroup) { console.writeline ("=========================================="); foreach (student stu in group) { conSole. WriteLine ("Team: {0} name: {1}", stu. Teamid, stu. -; } console.writeline ("=========================================="); } console.readkey (); } } }
GroupJoin ()
If we want to know how many students there are in a group, this is a one-to-many mapping, but a join is a one-to-one mapping that needs to be processed again after the call.
It is most reasonable to use GroupJoin () at this time. He corresponded the group ID to a group of students (multiple students).
using system; using system.collections.generic; using System.Linq;
using system.text; namespace testgroupjoinapi { class Program { public class Student { public string first { get; set; } public string Last { get; set; } public int ID { get; set; } public list&nbsP scores; public int TeamID { get; set; } } public class Team { public int TeamID { get; set; } public string teamname { get; set; } } // create a data source by using a collection initializer. static list students = new list { new student {first= "Svetlana", last= "Omelchenko", id=111, scores= new list {97, 92, 81, 60}, TeamID=0}, new student {first= "Claire", last= "O ' Donnell", id=112, scores= new list { 75, 84, 91, 39}, teamid=1}, new student {first= "Sven", last= "Mortensen", ID= 113, scores= new list {88, 94, 65, 91}, teamid=0}, new student {first= "Cesar", last= "GarciA ", id=114, scores= new list {97, 89, 85, 82}, teamid=1}, new student {first= "Debra", last= "Garcia," id=115, scores= new list {35, 72, 91. , 70}, teamid=0}, new student {first= "Fadi", last= "Fakhouri", id=116, scores= new List {99, 86, 90, 94}, TeamID=1}, new student {first= "Hanying", Last= "Feng", ID=117, Scores= new List {93, 92, 80, 87}, TeamID=0}, new student {first= "Hugo", Last= "Garcia," id=118, scores= new list {92, 90, 83, 78}, teamid=. 1}, new student {first= "Lance", last= "Tucker", id=119, scores= new list {68, 79, 88, 92}, TeamID=0}, new student {first= "Terry", last= "Adams", id=120, scores= new List {99, 82, 81, 79}, TeamID=1}, new student {first= "Eugene", last= " Zabokritski ", id=121, scores= new list {96, 85, 91, 60}, teamid=0 }, new student {first= " Michael ", &nbsP Last= "Tucker", id=122, scores= new list {94, 92, 91, 91}, teamid= 1 } }; // create a data source by using a collection initializer. static list
teams = new List { new team {teamid = 0, teamname= "Team a"}, new team {teamid = 1, teamname= "Team b"}, }; Static voiD main (String[] args) { var items = teams. GroupJoin ( students, team => team. teamid, student => student. teamid, (team, studentgroup) => new { team. teamid, team. teamname,
students = studentGroup &NBSP;&NBSP}); foreach (var item in items) { console.writeline ("team {0} : ", item). Teamname); foreach (student stu in item.students) { Console.WriteLine ("Name: {0}, {1}", stu. First, stu. Last); } console.writeline ("===================================================="); } &NBSP;&NBSP;&NBsp; console.readkey (); } } }