重视Linq技术_7
Projecting - Select
//1、Select-Subqueries and Object Hierarchies
string sampleDirectory = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
DirectoryInfo[] dirs = new DirectoryInfo (sampleDirectory).GetDirectories();
var query =
from d in dirs
where (d.Attributes & FileAttributes.System) == 0
select new
{
DirectoryName = d.FullName,
Created = d.CreationTime,
Files = from f in d.GetFiles()
where (f.Attributes & FileAttributes.Hidden) == 0
select new { FileName = f.Name, f.Length, }
};
query.Dump();
//2、Simple SelectMany
IEnumerable<string[]> query1 = fullNames.Select (name => name.Split());
IEnumerable<string> query2 = fullNames.SelectMany (name => name.Split());
query1.Dump ("A simple Select gives us a hierarchical result set");
query2.Dump ("SelectMany gives us a flat result set");
IEnumerable<string> query3 =
from fullName in fullNames
from name in fullName.Split() // Translates to SelectMany
select name;
query3.Dump ("Same SelectMany query, but in comprehension syntax");
![image image](https://images.cnblogs.com/cnblogs_com/sanic/201203/201203052155262734.png)
IEnumerable<string> query =
from fullName in fullNames // fullName = outer variable
from name in fullName.Split() // name = iteration variable
select name + " came from " + fullName;
query.Dump ("Both variables are in scope");
![image image](https://images.cnblogs.com/cnblogs_com/sanic/201203/201203052155267684.png)
IEnumerable<string> query1 =
from fullName in fullNames
from x in fullName.Split().Select (name => new { name, fullName } )
orderby x.fullName, x.name
select x.name + " came from " + x.fullName;
query1.Dump ("The intermediate solution");
IEnumerable<string> query2 = fullNames
.SelectMany (fName => fName.Split().Select (name => new { name, fName } ))
.OrderBy (x => x.fName)
.ThenBy (x => x.name)
.Select (x => x.name + " came from " + x.fName);
query2.Dump ("Final translation to lambda syntax");
![image image](https://images.cnblogs.com/cnblogs_com/sanic/201203/201203052155297911.png)
//5、NOTE - Another way to call SelectMany
string[] fullNames = { "Anne Williams", "John Fred Smith", "Sue Green" };
var query1 =
fullNames
.SelectMany (fName => fName.Split().Select (name => new { name, fName } ));
// We can re-write this as follows, and get the same result:
var query2 =
fullNames
.SelectMany (fName => fName.Split(), (fName, name) => new { name, fName } );
query1.Dump ("Using SelectMany+Select");
query2.Dump ("Using SelectMany with a collection selector + result selector");
//6、Cross Product Join - Filtered
IEnumerable<string> query =
from name1 in players
from name2 in players
where name1.CompareTo (name2) < 0
orderby name1, name2
select name1 + " vs " + name2;
query.Dump();
//7、LINQ to SQL - Outer Joins with SelectMany
(
from c in Customers
from p in c.Purchases
where p.Price > 1000
select new { c.Name, p.Description, p.Price }
)
.Dump ("An inner join");
(
from c in Customers
from p in c.Purchases.DefaultIfEmpty()
select new { c.Name, p.Description, Price = (decimal?) p.Price }
)
.Dump ("An outer join (without the predicate)");
Customer[] localCustomerCollection = Customers.ToArray();
var query =
from c in localCustomerCollection
from p in c.Purchases.DefaultIfEmpty()
select new
{
Descript = p == null ? null : p.Description,
Price = p == null ? (decimal?) null : p.Price
};
query.Dump();
左外联接:就是返回第一个集合的每个元素,而无论该元素在第二个集合中是否具有相关元素。可以使用 LINQ,通过对分组联接的
结果调用 DefaultIfEmpty 来执行左外部联接。
DefaultIfEmpty:通过使用延迟执行实现。即时返回值为一个对象,该对象存储执行操作所需的所有信息。
它有两个重载方法:1.返回指定序列的元素;如果序列为空,则返回单一实例集合中的类型参数的默认值。
2.返回指定序列中的元素;如果序列为空,则返回单一实例集合中的指定值。
(
from c in Customers
from p in c.Purchases.DefaultIfEmpty()
select new { c.Name, p.Description, Price = (decimal?) p.Price }
)
.Dump ("An outer join (without the predicate)");
Name | Description | Price |
---|---|---|
Mary |
Boat |
30000 |
Mary |
Camera |
1200 |
Bloggs |
null | null |
from c in Customers
from p in c.Purchases.Where (p => p.Price > 1000).DefaultIfEmpty()
select new
{
c.Name,
p.Description,
Price = (decimal?) p.Price
}
Name | Description | Price |
---|---|---|
Tom |
Holiday |
2000 |
Dick |
null | null |
Any:用于判断集合中是否有元素满足某一条件;不延迟。(若条件为空,则集合只要不为空就返回True,否则为False)。
有两个重载方法,分别为简单形式和带条件形式。
from c in Customers
join p in Purchases on c.ID equals p.CustomerID
into custPurchases
where custPurchases.Any()
select new
{
CustName = c.Name,
custPurchases
}
OrderBy
var names = new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }.AsQueryable();
names.OrderBy (s => s.Length).ThenBy (s => s)
.Dump ("By length, then alphabetically");
Group By
from p in Purchases
group p.Price by p.Date.Year into salesByYear
where salesByYear.Average (x => x) > 1000
select new
{
Year = salesByYear.Key,
TotalSales = salesByYear.Count(),
AvgSale = salesByYear.Average(),
TotalValue = salesByYear.Sum()
}
Concat and Union
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
seq1.Concat (seq2).Dump ("Concat");//1、2、3、3、4、5
seq1.Union (seq2).Dump ("Union");//1、2、3、4、5
Intersect and Except
int[] seq1 = { 1, 2, 3 }, seq2 = { 3, 4, 5 };
seq1.Intersect (seq2).Dump ("Intersect");//3
seq1.Except (seq2).Dump ("seq1.Except (seq2)");//1、2
seq2.Except (seq1).Dump ("seq2.Except (seq1)");//4、5
Cast and OfType
classicList.AddRange ( new int[] { 3, 4, 5 } );
DateTime offender = DateTime.Now;
classicList.Add (offender);
IEnumerable<int>
ofTypeSequence = classicList.OfType<int>(),
castSequence = classicList.Cast<int>();
ofTypeSequence.Dump ("Notice that the offending DateTime element is missing");
//Notice what the offending DateTime element does to the Cast sequence
//castSequence.Dump();
Element Operatiors
int[] numbers = { 1, 2, 3, 4, 5 };
numbers.First().Dump ("First");//1
numbers.Last().Dump ("Last");//5
numbers.FirstOrDefault (n => n > 10).Dump("FirstOrDefault(10)");//0
numbers.ElementAt (2).Dump ("ElementAt (2)");//3
numbers.ElementAtOrDefault (9).Dump ("ElementAtOrDefault (9)");//0
numbers.Single (n => n % 3 == 0).Dump ("The Single number divisible by 3");//3
numbers.SingleOrDefault (n => n > 10).Dump ("The SingleOrDefault number > 10");//0
Aggregation Methods
"pa55w0rd".Count (c => char.IsDigit (c)).Dump ("Count with predicate");//3
int[] numbers = { 28, 32, 14 };
numbers.Min().Dump ("Min");//14
numbers.Max().Dump ("Max");//28
numbers.Sum().Dump ("Sum");//74
numbers.Average().Dump ("Average (mean)");//24.7
Quantifies
new int[] { 2, 3, 4 }.Contains (3) .Dump ("Contains (3)");//True
new int[] { 2, 3, 4 }.Any (n => n == 3) .Dump ("Any (n => n == 3)");//True
new int[] { 2, 3, 4 }.Any (n => n > 10) .Dump ("Has a big number");//False
new int[] { 2, 3, 4 }.Where (n => n > 10).Any() .Dump ("Has a big number");//False
var query = "Hello".Distinct();
query.SequenceEqual ("Helo").Dump();
Customers.Where (c => c.Purchases.All (p => p.Price < 100))//ALL:用于判断集合中所有元素是否都满足某一条件;不延迟
Generation Methods
Enumerable.Range (5, 5).Dump ("Range"); //5、6、7、8、9
Enumerable.Repeat (5, 3).Dump ("Repeat");//5、5、5