C# 当中 LINQ 的常规用法(Lambda 方式)
仅以本篇博文记录 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
参数。在这个委托当中,可以传入 TSource
和 TCollection
让我们将主表的数据与从表进行合并。
标准用法如下:
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
指定的是分组所需要的的列/属性,最后的结果会是一个分组结果的序列。这个序列的值是使用 TKey
和 TSource
组成的分组结果,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 方式)的更多相关文章
- C# LINQ查询表达式用法对应Lambda表达式
C#编程语言非常优美,我个人还是非常赞同的.特别是在学习一段时间C#后发现确实在它的语法和美观度来说确实要比其它编程语言强一些(也可能是由于VS编译器的加持)用起来非常舒服,而且对于C#我觉得他最优美 ...
- Lambda方式左连接有Linq方式左连接
网上查到的直接使用Join+DefaultIfEmpty的方式是错误的,实际生成SQL是两表先内联接,然后再LEFT JOIN.经过查证,参考资料,最终得到如下两种方式的左连接写法: public v ...
- GridView的常规用法
GridView控件在Asp.net中相当常用,以下是控件的解释,有些是常用的,有些是偶尔用到的,查找.使用.记录,仅此而已.(最后附带DropDownList控件) ASP.NET中GridView ...
- mapreduce的cleanUp和setUp的特殊用法(TopN问题)和常规用法
一:特殊用法 我们上来不讲普通用法,普通用法放到最后.我们来谈一谈特殊用法,了解这一用法,让你的mapreduce编程能力提高一个档次,毫不夸张!!!扯淡了,让我们进入正题: 我们知道reduce和m ...
- QuickWebApi2:使用Lambda方式,完成对WebApi的开发和调用-文档的生成
续 QuickWebApi:使用Lambda方式,完成对WebApi的开发和调用 上一篇完成了主要的功能,本次修订主要重构了对接口文档的生成规范,使之可读性更佳,甚至可以作为接口文档进行发布(当然,在 ...
- 【python】-matplotlib.pylab常规用法
目的: 了解matplotlib.pylab常规用法 示例 import matplotlib.pylab as pl x = range(10) y = [i * i for i in x] pl. ...
- 基于 普通及Lambda方式实现策略模式
什么是策略模式 策略模式代表了解决一类算法的通用解决方案,你可以在运行时选择使用哪种方案.比如如何使用不同的条件(比如苹果的重量,或者颜色 )来筛选库存中的苹果.你可以将这一模式应用到更广泛的领域 , ...
- MarkDown的常规用法
MarkDown的常规用法 标题 # 一级标题 ## 二级标题 ... ###### 六级标题 列表 第二级 - 和 空格 + 和 空额 * 和 空格 第三级 代码块 多行代码块 3个` 回车 单行代 ...
- linq的一些用法总结
获取列表数据. IList<Model> list = dao.getmx(Model, pageInfo);//获取数据列表 1.将列表中id一样的数据进行group by分组,并返回序 ...
随机推荐
- nginx学习.第一部分
1.nginx的版本发布历史 2015年支持thread pool提供stream四层反向代理支持reuseport特性,支持http v2协议.完全可以替代LVS 2016年支持动态模块 2.ngi ...
- Java排序 - 不实用的几个排序算法 -- 睡眠排序、猴子排序、面条排序、珠排序
介绍几个不实用的排序算法,一来可以在学习时增加一些乐趣,放松一下自己,二来可以学习一下.思考一下这些算法失败在哪里,又是否存在一些好的地方? 睡眠排序 这是一个思想比较简单,脑洞巨大的算法 -- 我们 ...
- 通过Ajax来简单的实现局部刷新(主要为C#中使用的UpdatePanel控件和ScriptManager控件)
1. ScriptManager和UpdatePanel控件联合使用可以实现页面局部异步刷新的效果.UpdatePanel用来设置页面中局部异步刷新的区域,它必须依赖于ScriptManager,因为 ...
- [SQLite]SQLite URI配置
脱离新手文档使用SQLAlchemy配置sqlite,才发现sqlite的URI指定有点特别. https://github.com/mitsuhiko/flask-sqlalchemy/issues ...
- sqlserver安装检测不通过 (重新启动失败)
打开注册表,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager 删除“PendingFileRenameOperat ...
- IDEA使用Git传放项目
使用Git下载项目到IDEA工具上开发 1. 下载Git 软件工具 https://git-scm.com/ 2. 下载安装 3.打开IDEA 配置Git 4. 搜索Git 在登入 5.选择自己Git ...
- spring事务管理方式,aop
达内12 note unit 09 01 1.spring事务管理 2.spring提供了对事务管理支持 spring采用aop机制完成事务控制 可以实现在不修改原有组件代码情况下实现事务控制功能. ...
- 如何理解opencv, python-opencv 和 libopencv?
转: OpenCV is a computer vision library written using highly optimized C/C++ code. It makes use of ...
- 我的第一次做app的细节
第一次做一个app 发现 需要和前端沟通好而且 还要注意细节 效果图细节不要忘记 尽量多穿数据不要少传数据 而且 对接 注意细节
- 【转】priority_queue优先队列
转自:http://www.cppblog.com/shyli/archive/2007/04/06/21366.html http://www.cppblog.com/shyli/archive/2 ...