仅以本篇博文记录 LINQ 相关操作的基本知识,原型参考自 MSDN 相关知识,中间加以自己的理解与 DEMO。

1. IEnuemrable<T>.Select()

Select 方法比较简单,就是在原有序列的基础上,为每个元素建立一个新的输出形式(类型)。

标准用法如下:

public class TestClass
{
public string Name { get; set; } public int Age { get; set; }
} void Main()
{
var testList = new List<TestClass>
{
new TestClass{Name = "张三",Age = 18},
new TestClass{Name="李四",Age = 32},
new TestClass{Name="王二",Age = 24}
}; var selectResult = testList.Select(student => new
{
Name = student.Name,
NewAge = student.Age + 20
}); foreach (var student in selectResult)
{
Console.WriteLine($"姓名:{student.Name},新的年龄:{student.NewAge}");
}
}

输出结果:

姓名:张三,新的年龄:38
姓名:李四,新的年龄:52
姓名:王二,新的年龄:44

这样 newResult 的结果就是我们所投射出来新序列,同时 IEnumerbale<T>.Select() 也拥有 延迟执行 的特性,只会在我们需要用到的时候才会进行计算。

2. IEnumerable<T>.SelectMany()

SelectMany() 方法的作用则与 Select() 方法不同,SelectMany() 是用于将每个元素的子集合合并为一个新的集合。

标准用法如下:

void Main()
{
var demoList = new List<Demo>()
{
new Demo(){Names = new List<string>{"a","b","c","d"}},
new Demo(){Names = new List<string>{"e","f","g","h"}},
new Demo(){Names = new List<string>{"i","j","k","l"}},
new Demo(){Names = new List<string>{"m","n","o","p"}},
}; var selectResult = demoList.Select(item=>item.Names);
Console.WriteLine("Select 操作的结果...");
foreach(var selectItem in selectResult)
{
foreach(var value in selectItem)
{
Console.WriteLine($"Value:{value}");
}
} Console.WriteLine("================================");
Console.WriteLine("SelectMany 操作的结果..."); var selectManyResult = demoList.SelectMany(item=>item.Names);
foreach(var selectManyItem in selectManyResult)
{
Console.WriteLine($"Value:{selectManyItem}");
}
} public class Demo
{
public List<string> Names { get; set; }
}

在本例当中这两个方法分别输出的是 IEnumerable<List<string>>IEnumerable<string> ,这里就可以看出来 SelectionMany() 方法将子集合扁平化输出成一个结果集。

输出结果:

Select 操作的结果...
Value:a
Value:b
Value:c
Value:d
Value:e
Value:f
Value:g
Value:h
Value:i
Value:j
Value:k
Value:l
Value:m
Value:n
Value:o
Value:p
================================
SelectMany 操作的结果...
Value:a
Value:b
Value:c
Value:d
Value:e
Value:f
Value:g
Value:h
Value:i
Value:j
Value:k
Value:l
Value:m
Value:n
Value:o
Value:p

IEnumerable<T>.SelectMany() 还拥有另外一个重载方法,这个新的重载方法多了一个 resultSelector 参数。在这个委托当中,可以传入 TSourceTCollection 让我们将主表的数据与从表进行合并。

标准用法如下:

void Main()
{
Store[] stores = new Store[]
{
new Store()
{
Name = "App Store",
Products = new string[] {"iPhone 8", "iPhone 8s", "iPhone X"}
},
new Store()
{
Name = "Google Store",
Products = new string[] {"Pixel", "Pixel 2"}
}
}; var result = stores.SelectMany(store => store.Products, (store, product) => new
{
StoreName = store.Name,
ProductName = product
}); foreach(var item in result)
{
Console.WriteLine($"商店名称:{item.StoreName},产品名称:{item.ProductName}");
}
} class Store
{
public string Name { get; set; }
public string[] Products { get; set; }
}

输出结果:

商店名称:App Store,产品名称:iPhone 8
商店名称:App Store,产品名称:iPhone 8s
商店名称:App Store,产品名称:iPhone X
商店名称:Google Store,产品名称:Pixel
商店名称:Google Store,产品名称:Pixel 2

3. IEnuemrable<T>.Where()

IEnumerable<T>.Where(Func<T,bool>) 主要用于过滤序列当中需要的元素,与 Select() 一样也是拥有 延迟执行 的特性。

标准用法:

void Main()
{
var integers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = integers.Where(x => x >= 5); foreach (var @int in result)
{
Console.WriteLine($"整形数据:{@int}");
}
}

输出结果:

整形数据:5
整形数据:6
整形数据:7
整形数据:8
整形数据:9

4. IEnuemrable<T>.OrderBy() 与 IEnuemrable<T>.OrderByDescending()

上述两个方法主要用于针对序列进行排序操作,OrderBy() 方法是升序排列,而 OrderByDescending() 则是降序排列。

标准用法:

void Main()
{
var integers = new[] { 3, 1, 2, 8, 5, 6, 7, 4, 9 };
var orderByResult = integers.OrderBy(i=>i); Console.WriteLine("升序排列结果.");
foreach (var @int in orderByResult)
{
Console.WriteLine($"整形数据:{@int}");
} Console.WriteLine("降序排列结果.");
var orderByDescResult = integers.OrderByDescending(i => i);
foreach (var @int in orderByDescResult)
{
Console.WriteLine($"整形数据:{@int}");
}
}

输出结果:

升序排列结果.
整形数据:1
整形数据:2
整形数据:3
整形数据:4
整形数据:5
整形数据:6
整形数据:7
整形数据:8
整形数据:9
降序排列结果.
整形数据:9
整形数据:8
整形数据:7
整形数据:6
整形数据:5
整形数据:4
整形数据:3
整形数据:2
整形数据:1

除了上述的基本排序以外,有的时候我们可能会有几个条件一起进行排序操作,例如先按照年龄排序,之后再按照成绩排序。这个时候就可以使用到 IEnumerable<T>.ThenBy()IEnumerable<T>.ThenByDescending() 来继续进行排序。

标准用法:

public class Student
{
public string Name { get; set; } public int Age { get; set; } public int Score { get; set; }
} void Main()
{
// 初始化数据
var students = new List<Student>
{
new Student{Name="张三",Age=14,Score=120},
new Student{Name="李四",Age=17,Score=80},
new Student{Name="王二",Age=11,Score=170},
new Student{Name ="孙五",Age=21,Score=145}
}; // 首先按照成绩降序排序,然后按照年龄升序排序
Console.WriteLine("使用 Then XX 方法进行排序。");
var result = students.OrderByDescending(student=>student.Score).ThenBy(student=>student.Age);
// 输出排序结果
Output(result); // 如果不使用 ThenXX 进行排序,而直接使用 OrderXX 进行多个排序条件排序结果
Console.WriteLine("没有使用 Then XX 方法进行排序。");
var newResult = students.OrderByDescending(student => student.Score).OrderBy(student => student.Age);
Output(newResult); void Output(IEnumerable<Student> outputStudents)
{
foreach (var student in outputStudents)
{
Console.WriteLine($"学生名称:{student.Name},学生年龄:{student.Age},学生成绩:{student.Score}");
}
}
}

输出结果:

使用 Then XX 方法进行排序。
学生名称:王二,学生年龄:11,学生成绩:170
学生名称:孙五,学生年龄:21,学生成绩:145
学生名称:张三,学生年龄:14,学生成绩:120
学生名称:李四,学生年龄:17,学生成绩:80
没有使用 Then XX 方法进行排序。
学生名称:王二,学生年龄:11,学生成绩:170
学生名称:张三,学生年龄:14,学生成绩:120
学生名称:李四,学生年龄:17,学生成绩:80
学生名称:孙五,学生年龄:21,学生成绩:145

可以看到如果没有使用 ThenBy() 方法排序的结果,第一个条件根本没有起作用。所以在使用 LINQ 对序列进行排序的时候应该注意这一点,否则得到的结果可能与预期的不一样。

5. IEnuemrable<T>.GroupBy()

IEnumerable<T>.GroupBy() 方法主要用于将序列按照指定的列进行分组,这样我们就可以很方便对这些结果进行处理。

IEnumerable<T>.GroupBy() 方法一样是拥有八种不同参数的重载,但按照工作方式来说只有四类,只是每一类都会有一个支持 comparer 比较器的重载。

GroupBy() 方法拥有 延迟执行 特性。

下面的例子列举了不同重载的使用方法:

方法 1

public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);

keySelector 指定的是分组所需要的的列/属性,最后的结果会是一个分组结果的序列。这个序列的值是使用 TKeyTSource 组成的分组结果,TKey 指代的是用作分组的列/属性,而 TSource 也是一个序列,存储的是这个分组下的结果。

标准用法:

public class Student
{
public string Name { get; set; } public bool Graduation { get; set; } public int Age { get; set; } public int Score { get; set; } public string City { get; set; } public override string ToString()
{
return $"姓名:{Name},年龄:{Age},分数:{Score},是否毕业:{Graduation},城市:{City}";
}
} class Program
{
static void Main(string[] args)
{
var students = new List<Student>
{
new Student{Name = "张三",Age = 15,Score = 94,Graduation = true,City = "北京"},
new Student{Name = "李四",Age = 17,Score = 47,Graduation = false,City = "北京"},
new Student{Name = "王二",Age = 19,Score = 77,Graduation = false,City = "广州"},
new Student{Name = "孙五",Age = 14,Score = 14,Graduation = false,City = "上海"}
}; var groupByResult = students.GroupBy(x => x.City);
foreach (var item in groupByResult)
{
Console.WriteLine($"分组城市:{item.Key}");
foreach (var student in item)
{
Console.WriteLine(student.ToString());
}
}
}
}

输出结果:

分组城市:北京
姓名:张三,年龄:15,分数:94,是否毕业:True,城市:北京
姓名:李四,年龄:17,分数:47,是否毕业:False,城市:北京
分组城市:广州
姓名:王二,年龄:19,分数:77,是否毕业:False,城市:广州
分组城市:上海
姓名:孙五,年龄:14,分数:14,是否毕业:False,城市:上海

方法 2

public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector);

其第一个参数的意思与之前一样,用于指定分组条件。第二个 elementSelector 参数则是与 Select() 方法类似,可以指定输出的分组结果类型。

标准用法:

public class Student
{
public string Name { get; set; } public bool Graduation { get; set; } public int Age { get; set; } public int Score { get; set; } public string City { get; set; } public override string ToString()
{
return $"姓名:{Name},年龄:{Age},分数:{Score},是否毕业:{Graduation},城市:{City}";
}
} class Program
{
static void Main(string[] args)
{
var students = new List<Student>
{
new Student{Name = "张三",Age = 15,Score = 94,Graduation = true,City = "北京"},
new Student{Name = "李四",Age = 17,Score = 47,Graduation = false,City = "北京"},
new Student{Name = "王二",Age = 19,Score = 77,Graduation = false,City = "广州"},
new Student{Name = "孙五",Age = 14,Score = 14,Graduation = false,City = "上海"}
}; var groupByResult = students.GroupBy(x => x.City,student=>new{student.Name,student.City});
foreach (var item in groupByResult)
{
Console.WriteLine($"分组城市:{item.Key}");
foreach (var student in item)
{
Console.WriteLine($"姓名:{student.Name},城市:{student.City}");
}
}
}
}

输出结果:

标准用法:

分组城市:北京
姓名:张三,城市:北京
姓名:李四,城市:北京
分组城市:广州
姓名:王二,城市:广州
分组城市:上海
姓名:孙五,城市:上海

方法 3

public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TKey, IEnumerable<TSource>, TResult> resultSelector);

本方法重载与之前的方法不一样,没有了 elementSelector 参数,变成了 resultSelector 参数,并且其返回值也由 IEnumerable<IGrouping<TKey, TSource>> 变成了 IEnumerable<YResult>

在这个方法当中,我们只需要通过 resultSelector 委托即可指定需要输出的数据类型,这里该委托的 TKey 参数是分组的列/属性,而 IEnumerable<TSource> 则是每个分组结果的关联序列。

标准用法:

public class Student
{
public string Name { get; set; } public bool Graduation { get; set; } public int Age { get; set; } public int Score { get; set; } public string City { get; set; } public override string ToString()
{
return $"姓名:{Name},年龄:{Age},分数:{Score},是否毕业:{Graduation},城市:{City}";
}
} class Program
{
static void Main(string[] args)
{
var students = new List<Student>
{
new Student{Name = "张三",Age = 15,Score = 94,Graduation = true,City = "北京"},
new Student{Name = "李四",Age = 17,Score = 47,Graduation = false,City = "北京"},
new Student{Name = "王二",Age = 19,Score = 77,Graduation = false,City = "广州"},
new Student{Name = "孙五",Age = 14,Score = 14,Graduation = false,City = "上海"}
}; var groupByResult = students.GroupBy(x => x.City, (key, enumerable) =>
{
return new
{
City = key,
Avg = enumerable.Average(x => x.Score),
Max = enumerable.Max(x => x.Score)
};
}); foreach (var student in groupByResult)
{
Console.WriteLine($"城市:{student.City},平均分:{student.Avg},最高分:{student.Max}");
}
}
}

输出结果:

城市:北京,平均分:70.5,最高分:94
城市:广州,平均分:77,最高分:77
城市:上海,平均分:14,最高分:14

方法 4

public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector);

最后一个方法与之前的方法一样,不过多了 elementSelector,与第二个方法一样,用于指定要选择的属性字段,排除其他字段。

标准用法:

public class Student
{
public string Name { get; set; } public bool Graduation { get; set; } public int Age { get; set; } public int Score { get; set; } public string City { get; set; } public override string ToString()
{
return $"姓名:{Name},年龄:{Age},分数:{Score},是否毕业:{Graduation},城市:{City}";
}
} class Program
{
static void Main(string[] args)
{
var students = new List<Student>
{
new Student{Name = "张三",Age = 15,Score = 94,Graduation = true,City = "北京"},
new Student{Name = "李四",Age = 17,Score = 47,Graduation = false,City = "北京"},
new Student{Name = "王二",Age = 19,Score = 77,Graduation = false,City = "广州"},
new Student{Name = "孙五",Age = 14,Score = 14,Graduation = false,City = "上海"}
}; var groupByResult = students.GroupBy(x => x.City, x=>new{x.Name,x.City,x.Age,x.Score},(key, enumerable) =>
{
return new
{
City = key,
Avg = enumerable.Average(x => x.Score),
Max = enumerable.Max(x => x.Score),
AvgAge = enumerable.Average(x=>x.Age)
};
}); foreach (var student in groupByResult)
{
Console.WriteLine($"城市:{student.City},平均分:{student.Avg},最高分:{student.Max},平均年龄:{student.AvgAge}");
}
}
}

输出结果:

城市:北京,平均分:70.5,最高分:94,平均年龄:16
城市:广州,平均分:77,最高分:77,平均年龄:19
城市:上海,平均分:14,最高分:14,平均年龄:14

6. IEnuemrable<T>.Join()

IEnumerable<T>.Join() 方法一般用来连接两个不同的表进行关联查询,其方法定义大概如下。

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector);

假设我们拥有两张表,分别是员工表与联系方式表,都是通过一个 Id 相互关联。如果我们需要找到某个员工的联系方式,那么员工是主表则为 inner,而联系方式是从表,则为 outer 。另外两个 Selector 分别用于指定各自的关联属性。

IEnumerable<T>.Join() 拥有 延迟执行 的特性,并且是内连查询。

标准用法:

public class Person
{
public int Id { get; set; } public string Name { get; set; }
} public class ContactInformation
{
public int PersonId { get; set; } public string PhoneNumber { get; set; } public string Address { get; set; }
} class Program
{
static void Main(string[] args)
{
// 初始化员工信息
var persons = new[] {new Person {Id = 1, Name = "张三"}, new Person {Id = 2, Name = "李四"}, new Person {Id = 3, Name = "王二"}}; // 初始化员工的联系方式
var contactInfos = new[]
{
new ContactInformation {PersonId = 1, Address = "上海", PhoneNumber = "001-00001"},
new ContactInformation {PersonId = 2, Address = "北京", PhoneNumber = "002-00002"},
new ContactInformation {PersonId = 3, Address = "广州", PhoneNumber = "003-00003"},
new ContactInformation {PersonId = 1, Address = "深圳", PhoneNumber = "004-00004"}
}; var joinResult = contactInfos.Join(persons, contactInfo => contactInfo.PersonId, person => person.Id, (information, person) => new
{
Name = person.Name,
PhoneNumber = information.PhoneNumber,
Address = information.Address
}); foreach (var item in joinResult)
{
Console.WriteLine($"姓名:{item.Name},电话:{item.PhoneNumber},地址:{item.Address}");
}
}
}

输出结果:

姓名:张三,电话:001-00001,地址:上海
姓名:李四,电话:002-00002,地址:北京
姓名:王二,电话:003-00003,地址:广州
姓名:张三,电话:004-00004,地址:深圳

7. IEnuemrable<T>.GroupJoin()

以上一个 IEnumerable<T>.Join() 的方法结果为例,可以看到某个员工的联系方式数据有两笔甚至以上的时候就会拥有重复数据,这个时候就需要使用到 GroupJoin() 来进行处理。

public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);

GroupJoin() 方法与 Join() 类似,都是根据 outer 的关联字段与 inner 的关联字段相等的数据进行查询,并支持进行汇总操作。

GroupJoin() 方法也具有 延迟执行 的特性,并且通过 SelectMany() 方法与 DefaultIfEmpty() 方法可以实现 Left Join 的查询效果。

标准用法:

public class Person
{
public int Id { get; set; } public string Name { get; set; }
} public class ContactInformation
{
public int PersonId { get; set; } public string PhoneNumber { get; set; } public string Address { get; set; }
} class Program
{
static void Main(string[] args)
{
// 初始化员工信息
var persons = new[] {new Person {Id = 1, Name = "张三"}, new Person {Id = 2, Name = "李四"}, new Person {Id = 3, Name = "王二"}}; // 初始化员工的联系方式
var contactInfos = new[]
{
new ContactInformation {PersonId = 1, Address = "上海", PhoneNumber = "001-00001"},
new ContactInformation {PersonId = 2, Address = "北京", PhoneNumber = "002-00002"},
new ContactInformation {PersonId = 3, Address = "广州", PhoneNumber = "003-00003"},
new ContactInformation {PersonId = 1, Address = "深圳", PhoneNumber = "004-00004"}
}; var groupJoinResult = persons.GroupJoin(contactInfos, person => person.Id, contactInfo => contactInfo.PersonId, (person, infos) => new
{
Name = person.Name,
Phones = string.Join(',',infos.Select(x=>x.PhoneNumber))
}); foreach (var item in groupJoinResult)
{
Console.WriteLine($"姓名:{item.Name},电话:{item.Phones}");
}
}
}

输出结果:

姓名:张三,电话:001-00001,004-00004
姓名:李四,电话:002-00002
姓名:王二,电话:003-00003

扩展写法,使用 SelectMany()DefaultIfEmpty() 实现左连接查询。

public class Person
{
public int Id { get; set; } public string Name { get; set; }
} public class ContactInformation
{
public int PersonId { get; set; } public string PhoneNumber { get; set; } public string Address { get; set; }
} class Program
{
static void Main(string[] args)
{
// 初始化员工信息
var persons = new[] {new Person {Id = 1, Name = "张三"}, new Person {Id = 2, Name = "李四"}, new Person {Id = 3, Name = "王二"}}; // 初始化员工的联系方式
var contactInfos = new[]
{
new ContactInformation {PersonId = 1, Address = "上海", PhoneNumber = "001-00001"},
new ContactInformation {PersonId = 2, Address = "北京", PhoneNumber = "002-00002"},
// ContactInformation {PersonId = 3, Address = "广州", PhoneNumber = "003-00003"},
new ContactInformation {PersonId = 1, Address = "深圳", PhoneNumber = "004-00004"}
}; var groupJoinResult = persons.GroupJoin(contactInfos, person => person.Id, contactInfo => contactInfo.PersonId, (person, infos) => new
{
Name = person.Name,
ContactInfos = infos
}).SelectMany(x=>x.ContactInfos.DefaultIfEmpty(), (_, __) => new
{
PersonName = _.Name,
PhoneNumber = __?.PhoneNumber ?? null
}); foreach (var item in groupJoinResult)
{
Console.WriteLine($"姓名:{item.PersonName},电话:{item.PhoneNumber}");
}
}
}

输出结果:

姓名:张三,电话:001-00001
姓名:张三,电话:004-00004
姓名:李四,电话:002-00002
姓名:王二,电话:

8. IEnuemrable<T>.Skip()

IEnumerable<T>.Skip(int N) 方法的主要作用就是从序列首部跳过序列中 N 个元素,然后返回其结果,这个方法还有两个衍生的方法。

第一个是 IEnumerable<T>.SkipLast(int N) 方法,与 Skip(int N) 方法相反,它会从序列的尾部跳过 N 个元素再返回结果。

第二个则是 IEnumerbale<T>.SkipWhile(Func<T,bool> predicate) ,它可以传入一个过滤条件,当序列当中遇到第一个不满足条件的元素时,就会返回该元素及其后续的所有元素,而略过之前符合条件的元素。

标准用法:

class Program
{
static void Main()
{
void OutputResult(IEnumerable<int> ienumerable)
{
foreach (var item in ienumerable)
{
Console.WriteLine($"{item}");
}
} var integers = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // Skip() 方法演示。
Console.WriteLine("Skip() 方法演示:");
var skipResult = integers.Skip(5);
OutputResult(skipResult); // SkipLast() 方法演示。
Console.WriteLine("SkipLast() 方法演示:");
var skipLastResult = integers.SkipLast(5);
OutputResult(skipLastResult); // SkipWhile() 方法演示。
Console.WriteLine("SkipWhile() 方法演示:");
var skipWhileResult = integers.SkipWhile(@int => @int != 3);
OutputResult(skipWhileResult);
}
}

输出结果:

Skip() 方法演示:
6
7
8
9
10
SkipLast() 方法演示:
1
2
3
4
5
SkipWhile() 方法演示:
3
4
5
6
7
8
9
10

9. IEnuemrable<T>.Take()

IEnumerable<T>.Take(int N) 方法的作用是从序列首部选取 N 个元素返回结果。

它也拥有两个衍生的方法,第一个是 IEnumerable<T>.TakeLast(int N) 方法,与 Skip(int N) 方法相同。这个方法主要是从序列的尾部选取 N 个元素组成一个新的序列并返回其结果。

第二个方法也是相似,叫做 IEnumerable<T>.TakeWhile(Func<T,bool>) ,与 IEnumerable<T>.Skip(Func<T,bool>) 方法相反,本方法是会从序列首部开始获取元素,直到条件满足时就会停止获取,然后将这些结果返回成为一个新的序列。

标准用法:

class Program
{
static void Main()
{
void OutputResult(IEnumerable<int> ienumerable)
{
foreach (var item in ienumerable)
{
Console.WriteLine($"{item}");
}
} var integers = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // Take() 方法演示。
Console.WriteLine("Take() 方法演示:");
var skipResult = integers.Take(5);
OutputResult(skipResult); // TakeLast() 方法演示。
Console.WriteLine("TakeLast() 方法演示:");
var skipLastResult = integers.Take(3);
OutputResult(skipLastResult); // TakeWhile() 方法演示。
Console.WriteLine("TakeWhile() 方法演示:");
var skipWhileResult = integers.TakeWhile(@int => @int != 3);
OutputResult(skipWhileResult);
}
}

输出结果:

Take() 方法演示:
1
2
3
4
5
TakeLast() 方法演示:
1
2
3
TakeWhile() 方法演示:
1
2

10. IEnuemrable<T>.Aggregate()

IEnumerable<T>.Aggregate() 方法的主要作用是帮助开发人员对一个序列的资料进行汇总处理,即会执行 N 次,每次会将之前的汇总结果与当前元素的值传入到一个 Func<TSource, TSource, TSource> 委托当中,其返回值就会作为新的汇总结果传递给下一个元素。

IEnumerable<T>.Aggregate() 共有 3 个重载方法,其运行机制与上述说明一致,只是在于初始化操作和返回值的时候不太一致。

public static TSource Aggregate<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func);

其中 func 参数是每次执行汇总操作时的逻辑方法,第一个参数则是之前的汇总结果,第二个参数即是当前元素的值,最后一个返回值则是汇总完成的结果,将会作为下一次汇总操作时的传入参数。(即第一个参数的值)

public static TAccumulate Aggregate<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func);

其中 seed 是汇总结果的初始值,这个值将会在第一次计算汇总结果的时候用到。

public static TResult Aggregate<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector);

本方法与上一个方法类似,不同的是有一个 resultSelector 委托可以方便我们将数据重新投射到不同的类型当中去。

标准用法:

class Program
{
void OutputResult(IEnumerable<int> ienumerable)
{
foreach (var item in ienumerable)
{
Console.WriteLine($"{item}");
}
} static void Main(string[] args)
{
var integers = new[] {3, 2, 1, 7, 10, 6, 4, 8, 9, 5}; // IEnumerable<T>.Sum(x=>x) 效果,计算整个序列元素之和。
var sumResult = integers.Aggregate((totalCount, nextItem) => totalCount + nextItem);
Console.WriteLine($"序列求和结果:{sumResult}"); // IEnumerable<T>.Min(x=>x) 效果,计算整个序列当中的最小元素。
var minResult = integers.Aggregate((min, next) => min > next ? next : min);
Console.WriteLine($"序列当中的最小值:{minResult}"); // IEnumerable<T>.Max(x=>x) 效果,计算整个序列当中最大的元素。
var maxResult = integers.Aggregate((max, next) => max < next ? next : max);
Console.WriteLine($"序列当中的最大值:{maxResult}"); // IEnumerable<T>.Count() 效果,计算整个序列当中的元素数量。
var countResult = integers.Aggregate(0,(count, next) => ++count);
Console.WriteLine($"序列当中的元素数量:{countResult}"); // IEnumerable<T>.Average(x=>) 效果,计算整个序列当中的平均数。
int enumerableCount = 0;
var averageResult = integers.Aggregate(0, (total, next) =>
{
total += next;
enumerableCount++;
return total;
},total=>new
{
averageValue = total / enumerableCount
}); Console.WriteLine($"序列的平均值:{averageResult.averageValue}");
}
}

输出结果:

序列求和结果:55
序列当中的最小值:1
序列当中的最大值:10
序列当中的元素数量:10
序列的平均值:5

C# 当中 LINQ 的常规用法(Lambda 方式)的更多相关文章

  1. C# LINQ查询表达式用法对应Lambda表达式

    C#编程语言非常优美,我个人还是非常赞同的.特别是在学习一段时间C#后发现确实在它的语法和美观度来说确实要比其它编程语言强一些(也可能是由于VS编译器的加持)用起来非常舒服,而且对于C#我觉得他最优美 ...

  2. Lambda方式左连接有Linq方式左连接

    网上查到的直接使用Join+DefaultIfEmpty的方式是错误的,实际生成SQL是两表先内联接,然后再LEFT JOIN.经过查证,参考资料,最终得到如下两种方式的左连接写法: public v ...

  3. GridView的常规用法

    GridView控件在Asp.net中相当常用,以下是控件的解释,有些是常用的,有些是偶尔用到的,查找.使用.记录,仅此而已.(最后附带DropDownList控件) ASP.NET中GridView ...

  4. mapreduce的cleanUp和setUp的特殊用法(TopN问题)和常规用法

    一:特殊用法 我们上来不讲普通用法,普通用法放到最后.我们来谈一谈特殊用法,了解这一用法,让你的mapreduce编程能力提高一个档次,毫不夸张!!!扯淡了,让我们进入正题: 我们知道reduce和m ...

  5. QuickWebApi2:使用Lambda方式,完成对WebApi的开发和调用-文档的生成

    续 QuickWebApi:使用Lambda方式,完成对WebApi的开发和调用 上一篇完成了主要的功能,本次修订主要重构了对接口文档的生成规范,使之可读性更佳,甚至可以作为接口文档进行发布(当然,在 ...

  6. 【python】-matplotlib.pylab常规用法

    目的: 了解matplotlib.pylab常规用法 示例 import matplotlib.pylab as pl x = range(10) y = [i * i for i in x] pl. ...

  7. 基于 普通及Lambda方式实现策略模式

    什么是策略模式 策略模式代表了解决一类算法的通用解决方案,你可以在运行时选择使用哪种方案.比如如何使用不同的条件(比如苹果的重量,或者颜色 )来筛选库存中的苹果.你可以将这一模式应用到更广泛的领域 , ...

  8. MarkDown的常规用法

    MarkDown的常规用法 标题 # 一级标题 ## 二级标题 ... ###### 六级标题 列表 第二级 - 和 空格 + 和 空额 * 和 空格 第三级 代码块 多行代码块 3个` 回车 单行代 ...

  9. linq的一些用法总结

    获取列表数据. IList<Model> list = dao.getmx(Model, pageInfo);//获取数据列表 1.将列表中id一样的数据进行group by分组,并返回序 ...

随机推荐

  1. 《ServerSuperIO Designer IDE使用教程》-4.增加台达PLC驱动及使用教程,从0到1的改变。发布:v4.2.3版本

    v4.2.3 更新内容:1.优化数据存储部分,提高效率.2.修复数据库服务停止造成程序异常退出的现象.3.修复本机没有串口造成无法增加设备驱动的情况.4.增加编辑设备和监测点配置信息功能.5.增加台达 ...

  2. VS 中 无法嵌入互操作类型“……”,请改用适用的接口的解决方法

    在引用COM组件的时候,出现了无法嵌入互操作类型"--",请改用适用的接口的错误提示. 选中项目中引入的dll,鼠标右键,选择属性,把"嵌入互操作类型"设置为F ...

  3. Linux从入门到进阶全集——【第十四集:Shell基础命令】

    1,Shell就是命令行执行器 2,作用:将外层引用程序的例如ls ll等命令进行解释成01表示的二进制代码给内核,从而让硬件执行:硬件的执行结果返回给shell,shell解释成我们能看得懂的代码返 ...

  4. android studio 开发免安装的app之目录结构

    尚未深入分析,暂且外链到我看到的,对此有帮助的博客,在此,感谢你们. 1.https://blog.csdn.net/tscyds/article/details/74331085 2.https:/ ...

  5. 通过zabbix的API接口获取服务器列表

    Zabbix API说明 1) 基于Web的API,作为Web前端的一部分提供,使用JSON-RPC 2.0协议 2) 身份认证Token:在访问Zabbix中的任何数据之前,需要登录并获取身份验证令 ...

  6. scrapy 教程

    pip install Scrapy 结果报错,那就一个一个安装吧 一.安装  1.pip install wheel 后面的都一样 pip install lxml pip install pyop ...

  7. 极速创建 IOS APP !涛舅舅苹果 IOS APP自助生成系统!不用证书、不用越狱、永久可用

    不用签名将网页封装成苹果APP,无需苹果企业签名,IPA签名,ios签名,免越狱安装 (本方法只支持网站封装app,原生的用不了,详细请咨询客服) 近期很多朋友问我把网站变成app的方法,原因很多种, ...

  8. Linux 查询服务数据

    1.  htop 可以时时查看 2. free -m 查看缓存

  9. TypeScript 函数-重载

    function attr(name:string):string; function attr(age:number):string; function attr(nameorage:any):an ...

  10. 解决iPhone Safari 兼容性CSS背景显示不全问题

    https://jingyan.baidu.com/article/ca2d939d014ccbeb6c31ceb7.html 看到了这个文章解决的.中心部分小于980的时候回出现.苹果手机中的saf ...