Select
当谈到 C# LINQ 的 Select 方法时,它是一个非常强大的工具,可以用于各种不同的用途。下面是一些常见的用法:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
List<string> strings = numbers.Select(n => "Number " + n.ToString()).ToList();
在上述示例中,我们使用 Select 将整数列表 numbers 转换为字符串列表 strings,其中每个元素都以 "Number " 开头。
List<Person> people = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Charlie", Age = 40 }
};
var anonymousObjects = people.Select(p => new { FirstName = p.Name, AgeCategory = p.Age <= 30 ? "Young" : "Old" }).ToList();
在上述示例中,我们有一个包含人员信息的人员列表 people。使用 Select,我们将每个人员投影到一个匿名类型中,并只选择 Name 和 AgeCategory 属性。
List<string> animals = new List<string> { "cat", "dog", "bird" };
string concatenatedString = string.Join(", ", animals.Select(a => $"I love {a}"));
在上述示例中,我们使用 Select 将集合中的每个动物名称转换为一个带有字符串插值的句子,并使用 string.Join 将这些句子连接为一个字符串。
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
int sumOfSquares = numbers.Select(n => n * n).Sum();
int maxNumber = numbers.Select(n => n * 2).Max();
在上述示例中,我们使用 Select 将每个数字平方,并使用 Sum 和 Max 方法分别计算平方值的总和和最大值。
SelectMany
SelectMany 是 LINQ 中的一个方法,用于将嵌套的集合(集合的集合)转换为单个扁平的序列。它可以将嵌套结构的序列展平为单个序列,使操作更便捷。
以下是 SelectMany 方法的语法:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);
SelectMany 方法接受一个源序列以及一个返回子序列的函数,并将每个元素的子序列连接起来。它返回一个实现了 IEnumerable 接口的延迟执行的查询结果序列。
这是一个使用 SelectMany 方法的示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<List<int>> nestedNumbers = new List<List<int>>
{
new List<int> { 1, 2, 3 },
new List<int> { 4, 5, 6 },
new List<int> { 7, 8, 9 }
};
// 使用 SelectMany 方法将所有子序列连接成一个平坦的序列
IEnumerable<int> flattenedNumbers = nestedNumbers.SelectMany(x => x);
// 遍历平坦的序列
foreach (int number in flattenedNumbers)
{
Console.WriteLine(number);
}
}
}
在上述示例中,我们创建了一个嵌套的整数列表 nestedNumbers,其中包含三个子列表。然后,我们使用 SelectMany 方法将这些子列表连接成一个平坦的整数序列。
Take
在 C# 的 LINQ 中,Take 是用于从集合中获取指定数量的元素的方法。它可以用来限制查询结果的大小或获取集合中的前几个元素。
Take 方法的语法如下:
IEnumerable<T> Take<T>(this IEnumerable<T> source, int count)
其中,source 是要操作的集合本身,count 是要获取的元素数量。
下面是 Take 方法的几个用法示例:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> firstThreeNumbers = numbers.Take(3);
在上述示例中,我们使用 Take 方法获取了 numbers 集合的前三个元素(即 1、2 和 3)。
List<string> names = new List<string> { "Alice", "Bob", "Charlie", "David", "Eve" };
IEnumerable<string> limitedNames = names.Take(2);
在上述示例中,我们使用 Take 方法限制了查询结果最多只能包含前两个元素(即 “Alice” 和 “Bob”)。
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> evenNumbers = numbers.Where(n => n % 2 == 0).Take(2);
在上述示例中,我们先使用 Where 方法筛选出偶数,然后再使用 Take 方法获取前两个偶数。
需要注意的是,Take 方法不会修改原始集合,它只返回一个包含指定数量元素的新的可枚举序列。
TakeWhile
在 TakeWhile 方法中,它会根据指定的条件逐个获取元素,直到遇到第一个不满足条件的元素为止。
以下是正确的示例:
List<int> numbers = new List<int> { 2, 4, 6, 1, 8, 10 };
IEnumerable<int> consecutiveEvenNumbers = numbers.TakeWhile(n => n % 2 == 0);
在此示例中,使用 TakeWhile 方法获取 numbers 列表中连续的偶数元素。返回的结果是 2、4 和 6,因为在第一个奇数 1 出现后,就停止获取。
Take
在LINQ中,Skip方法用于跳过序列中指定数量的元素,并返回剩余的元素。它允许你忽略集合的前几个元素,从指定位置开始获取后续的元素。
Skip方法的语法如下:
IEnumerable<T> Skip<T>(this IEnumerable<T> source, int count)
其中,source是要操作的集合本身,count是要跳过的元素数量。
跳过指定数量的元素:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> remainingNumbers = numbers.Skip(2);
在上述示例中,我们使用Skip方法跳过了集合numbers中的前两个元素。返回的结果是3、4、5。
SkipWhile
在LINQ中,SkipWhile方法用于跳过序列中满足指定条件的连续元素,并返回剩余的元素。它允许你跳过集合中一系列符合条件的元素,直到遇到不满足条件的元素为止。
SkipWhile方法的语法如下:
IEnumerable<T> SkipWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate)
其中,source是要操作的集合本身,predicate是一个用于确定是否要跳过当前元素的函数。
以下是SkipWhile方法的几个用法示例:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> remainingNumbers = numbers.SkipWhile(n => n < 3);
在上述示例中,我们使用SkipWhile方法跳过集合numbers中满足条件n < 3的连续元素。返回的结果是3、4、5,因为在遇到第一个不满足条件的元素3后,停止跳过。
List<int> numbers = new List<int> { 1, 2, 5, 3, 4 };
IEnumerable<int> remainingNumbers = numbers.SkipWhile((n, index) => n < index);
在上述示例中,我们在SkipWhile方法的条件函数中使用了元素以及索引。条件n < index表示跳过元素值小于索引值的连续元素。返回的结果是5、3、4,因为在遇到第一个不满足条件的元素5后,停止跳过。
List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };
IEnumerable<string> remainingFruits = fruits.Where(f => f.Length > 5).SkipWhile(f => f.StartsWith("b"));
在上述示例中,我们先使用Where方法筛选出长度大于5的水果,然后再使用SkipWhile方法跳过以字母"b"开头的连续水果。返回的结果是"cherry"、“date”,因为在遇到第一个不以"b"开头的元素"cherry"后,停止跳过。
需要注意的是,SkipWhile方法在遇到第一个不满足条件的元素后,就会停止跳过。如果所有元素都满足条件,那么将返回一个空集合
在LINQ中,Join方法用于将两个集合(内连接)或多个集合(联接)基于共享的键关联起来。Join方法通过匹配两个集合中具有相同键的元素,生成一个新的结果集。
Join方法的基本语法如下:
IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector
)
其中,outer和inner是要联接的两个集合,outerKeySelector和innerKeySelector是用于提取键的函数,resultSelector用于生成结果元素。
Join
以下是Join方法的几个用法示例:
List<Person> persons = new List<Person>
{
new Person { Id = 1, Name = "Alice" },
new Person { Id = 2, Name = "Bob" },
new Person { Id = 3, Name = "Charlie" }
};
List<Salary> salaries = new List<Salary>
{
new Salary { PersonId = 1, Amount = 5000 },
new Salary { PersonId = 2, Amount = 6000 },
new Salary { PersonId = 4, Amount = 4000 }
};
var result = persons.Join(
salaries,
person => person.Id,
salary => salary.PersonId,
(person, salary) => new { Name = person.Name, Amount = salary.Amount }
);
在上述示例中,我们通过Join方法将persons和salaries两个集合内连接起来,基于Id和PersonId的匹配关系。返回的结果是一个匿名类型的集合,包含具有相匹配的Id和PersonId的元素。
List<Order> orders = new List<Order>
{
new Order { OrderId = 1, Product = "Apple", Quantity = 5 },
new Order { OrderId = 2, Product = "Banana", Quantity = 3 },
new Order { OrderId = 3, Product = "Apple", Quantity = 2 },
};
List<Invoice> invoices = new List<Invoice>
{
new Invoice { InvoiceId = 1, Product = "Apple", Amount = 20 },
new Invoice { InvoiceId = 2, Product = "Banana", Amount = 15 },
new Invoice { InvoiceId = 3, Product = "Cherry", Amount = 10 },
};
List<Customer> customers = new List<Customer>
{
new Customer { CustomerId = 1, Name = "Alice" },
new Customer { CustomerId = 2, Name = "Bob" },
};
var result = customers
.Join(
orders,
customer => customer.CustomerId,
order => order.CustomerId,
(customer, order) => new { customer.Name, order.OrderId, order.Quantity }
)
.Join(
invoices,
o => o.OrderId,
invoice => invoice.InvoiceId,
(o, invoice) => new { o.Name, o.OrderId, o.Quantity, invoice.Amount }
);
在上述示例中,我们通过两个Join方法进行多个集合的内连接。首先,我们将customers和orders两个集合按照CustomerId和OrderId进行连接,然后将结果再与invoices集合按照OrderId和InvoiceId进行连接。返回的结果是一个具有联接结果的匿名类型的集合。
需要注意的是,Join方法会返回所有满足联接条件的元素。如果两个集合中没有匹配的元素,则不会生成任何结果。
GroupJoin
LINQ中的GroupJoin操作是一种用于将两个数据源进行关联的机制。它根据两个数据源中的一个或多个键来对它们进行关联,并将结果分组。
GroupJoin操作的语法如下:
var result = outer.Join(
inner,
outerKey => outerKeyProperty,
innerKey => innerKeyProperty,
(outerItem, innerItems) => new
{
Outer = outerItem,
Inner = innerItems
});
其中:
outer:外部数据源(左表)
inner:内部数据源(右表)
outerKeyProperty:外部数据源中用于关联的属性或键
innerKeyProperty:内部数据源中用于关联的属性或键
outerItem:外部数据源中的项
innerItems:与外部数据源中的项关联的内部数据源中的项
result:用于存储结果的变量
请注意,以上代码创建了一个匿名类型(new { Outer = outerItem, Inner = innerItems })作为结果的类型。可以根据需要调整选择器函数来定义结果类型。
GroupJoin操作将根据给定的键,对外部数据源和内部数据源进行关联,并生成一个包含外部数据源项和相应内部数据源项列表的结果。列表可以是空的,如果没有匹配的项。
假设我们有两个实体类,Department(部门)和Employee(员工):
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Employee
{
public int DepartmentId { get; set; }
public string Name { get; set; }
}
现在我们创建一些部门和员工的示例数据:
var departments = new List<Department>
{
new Department { Id = 1, Name = "HR" },
new Department { Id = 2, Name = "Finance" },
new Department { Id = 3, Name = "IT" }
};
var employees = new List<Employee>
{
new Employee { DepartmentId = 2, Name = "John" },
new Employee { DepartmentId = 1, Name = "Alice" },
new Employee { DepartmentId = 1, Name = "Bob" },
new Employee { DepartmentId = 3, Name = "Charlie" }
};
现在,我们可以使用GroupJoin操作将这两个数据源进行关联,并按照部门进行分组:
var result = departments.GroupJoin(
employees,
department => department.Id,
employee => employee.DepartmentId,
(department, employeeGroup) => new
{
Department = department,
Employees = employeeGroup
});
在上面的代码中,我们传入了四个参数给GroupJoin操作:
外部数据源:departments
内部数据源:employees
外部关联键:department.Id
内部关联键:employee.DepartmentId
选择器函数选择了一个匿名类型,其中包含部门对象和与部门关联的员工列表。
最后,我们可以遍历结果并输出每个部门及其对应的员工列表:
foreach (var item in result)
{
Console.WriteLine("Department: " + item.Department.Name);
Console.WriteLine("Employees: " + string.Join(", ", item.Employees.Select(e => e.Name)));
Console.WriteLine();
}
这个示例中的输出将为每个部门打印部门名称和其相应的员工列表。
OrderBy
在LINQ中,OrderBy操作用于对数据源进行升序排序。使用OrderBy操作可以根据指定的排序键对数据进行排序,并返回一个新的有序序列。
下面是OrderBy操作的示例:
假设我们有一个Person类,每个Person对象都有一个Name属性和一个Age属性:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
我们创建一些Person对象的示例数据:
var people = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "John", Age = 30 },
new Person { Name = "Bob", Age = 20 },
new Person { Name = "Charlie", Age = 35 }
};
现在,我们可以使用OrderBy操作对Person对象进行按照姓名(Name)排序:
var sortedPeople = people.OrderBy(person => person.Name);
在上面的代码中,OrderBy操作传入了一个lambda表达式,通过person => person.Name指定了排序键。这意味着我们根据Person对象的Name属性进行排序。
如果我们想要按照年龄(Age)进行排序,可以使用以下代码:
var sortedPeople = people.OrderBy(person => person.Age);
同样的,OrderBy操作根据Person对象的Age属性进行排序。
最后,我们可以使用foreach循环遍历排序后的结果并对其进行输出:
foreach (var person in sortedPeople)
{
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
这个示例中,我们遍历排序后的结果并输出每个Person对象的姓名和年龄。
注意,OrderBy操作是升序排序。如果你想进行降序排序,可以使用OrderByDescending操作。
以下是OrderBy方法的重载版本示例:
// 定义一个整数数组
int[] numbers = { 5, 2, 8, 1, 3 };
// 使用OrderBy进行降序排序
var sortedNumbers = numbers.OrderByDescending(num => num);
// 遍历排序后的结果
foreach (var num in sortedNumbers)
{
Console.WriteLine(num);
}
在上述示例中,我们使用OrderByDescending方法对整数数组numbers按照元素的降序进行排序,并将排序后的结果存储在sortedNumbers变量中。然后通过foreach循环遍历sortedNumbers,打印排序后的结果。
除了OrderByDescending方法,除了按照数字进行排序外,还可以使用其他的重载版本来进行自定义排序。例如:
// 定义一个自定义的排序规则
class PersonComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Age.CompareTo(y.Age);
}
}
// 定义一个Person类型的对象集合
List<Person> persons = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Charlie", Age = 20 }
};
// 使用自定义的排序规则进行排序
var sortedPersons = persons.OrderBy(person => person, new PersonComparer());
// 遍历排序后的结果
foreach (var person in sortedPersons)
{
Console.WriteLine($"{person.Name} - {person.Age}");
}
在上述示例中,我们定义了一个自定义的排序规则PersonComparer,它实现了IComparer接口,并根据Person对象的Age属性进行排序。然后我们使用OrderBy方法,并传入自定义的排序规则,对persons集合进行排序并将结果存储在sortedPersons变量中。最后通过foreach循环遍历sortedPersons,打印排序后的结果。
OrderByDescending
LINQ的OrderByDescending方法用于对集合进行降序排序操作。它与OrderBy方法类似,但是结果是按照指定的排序规则进行降序排序,而不是升序排序。
OrderByDescending方法的语法如下:
public static IEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
参数说明:
source:要排序的源集合,类型为IEnumerable。
keySelector:一个委托,用于指定排序的关键字。它会接收源集合的每个元素作为输入,返回一个用于排序的关键字。关键字的类型可以是元素本身的类型,也可以是一个衍生类型。
返回值:
OrderByDescending方法返回一个排序后的IEnumerable类型的集合。
示例使用:
下面是一个示例,演示如何使用OrderByDescending方法对一个整数集合进行降序排序:
int[] numbers = { 5, 2, 8, 1, 3 };
var sortedNumbers = numbers.OrderByDescending(num => num);
foreach (var num in sortedNumbers)
{
Console.WriteLine(num);
}
在上述示例中,我们有一个整数数组numbers。我们使用OrderByDescending方法并提供一个lambda表达式num => num作为keySelector,它指定了按照整数本身进行排序。OrderByDescending方法返回一个排序后的IEnumerable集合,我们通过foreach循环遍历并打印排序后的结果。
自定义排序规则:
与OrderBy方法类似,OrderByDescending方法也可以自定义排序规则来进行排序操作。
以下示例演示如何按照字符串长度进行降序排序:
string[] fruits = { "orange", "apple", "banana", "cherry" };
var sortedFruits = fruits.OrderByDescending(fruit => fruit.Length);
foreach (var fruit in sortedFruits)
{
Console.WriteLine(fruit);
}
在这个示例中,我们使用OrderByDescending方法,并提供一个lambda表达式fruit => fruit.Length作为keySelector。这意味着我们将根据字符串的长度进行降序排序。OrderByDescending方法将返回一个排序后的IEnumerable集合,我们通过foreach循环遍历并打印排序后的结果。
ThenBy
LINQ的ThenBy方法用于对已经进行排序的集合进行进一步排序操作,以添加排序的次要条件。它可以在使用OrderBy或OrderByDescending方法之后进行调用,用于指定下一个排序规则。
ThenBy方法的语法如下:
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector);
参数说明:
source:已经排序的源集合,类型为IOrderedEnumerable。通常是在使用OrderBy或OrderByDescending方法之后调用ThenBy方法。
keySelector:一个委托,用于指定排序的次要关键字。它接收源集合的每个元素作为输入,返回一个用于排序的次要关键字。关键字的类型可以是元素本身的类型,也可以是一个衍生类型。
返回值:
ThenBy方法返回一个IOrderedEnumerable类型的集合,表示已经进行了进一步排序的集合,以添加了次要排序条件。
示例使用:
下面是一个示例,展示如何使用ThenBy方法对字符串集合进行多级排序:
string[] fruits = { "apple", "banana", "cherry", "date", "elderberry" };
var sortedFruits = fruits.OrderBy(fruit => fruit.Length)
.ThenBy(fruit => fruit);
foreach (var fruit in sortedFruits)
{
Console.WriteLine(fruit);
}
在上述示例中,我们有一个字符串数组fruits。我们使用OrderBy方法对字符串集合按照长度进行升序排序,并得到一个已排序的IOrderedEnumerable类型的集合。然后我们使用ThenBy方法,并提供一个lambda表达式fruit => fruit作为keySelector,它指定了在长度相同的情况下按照字符串本身进行升序排序。ThenBy方法将返回一个进一步排序后的IOrderedEnumerable集合,我们通过foreach循环遍历并打印多级排序后的结果。
多级排序:
我们可以在ThenBy方法中调用多次,以添加多个排序条件,从而实现多级排序。
以下示例演示如何对一个Person对象集合进行多级排序:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
List<Person> persons = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Alice", Age = 20 }
};
var sortedPersons = persons.OrderBy(person => person.Name)
.ThenBy(person => person.Age);
foreach (var person in sortedPersons)
{
Console.WriteLine($"{person.Name} - {person.Age}");
}
在这个示例中,我们有一个Person对象的集合。我们使用OrderBy方法对Person集合按照Name属性进行升序排序,然后使用ThenBy方法对排序结果再按照Age属性进行升序排序。最终得到一个多级排序后的IOrderedEnumerable集合,我们通过foreach循环遍历并打印排序结果。
Concat
当使用 LINQ 的 Concat 方法时,它会将两个集合(或序列)合并成一个新的集合。Concat 方法返回的是一个包含连接结果的新集合,原始集合并不会受到影响。
Concat 方法的语法如下:
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
参数:
first:表示要连接的第一个集合。
second:表示要连接的第二个集合。
返回值:
返回一个实现 IEnumerable 接口的对象,其中包含了两个集合的连接结果。
下面是一个更详细的 Concat 方法解析的示例:
var numbers1 = new List<int> { 1, 2, 3 };
var numbers2 = new List<int> { 4, 5, 6 };
var combinedNumbers = numbers1.Concat(numbers2);
foreach (var number in combinedNumbers)
{
Console.WriteLine(number);
}
输出结果为:
1
2
3
4
5
6
在上述示例中,Concat 方法将两个整数列表 numbers1 和 numbers2 连接在一起,形成了一个新的集合 combinedNumbers。通过 foreach 循环遍历 combinedNumbers,逐个输出连接后的结果。
需要注意的是,Concat 方法会创建一个新的集合,并将第一个集合的所有元素以及第二个集合的所有元素按顺序添加到新集合中。在连接过程中,不会进行去重操作,即使两个集合中包含相同的元素,也会全部保留。
此外,Concat 方法还可以连接多个集合,你可以依次传递多个集合作为参数。例如:
var numbers1 = new List<int> { 1, 2, 3 };
var numbers2 = new List<int> { 4, 5, 6 };
var numbers3 = new List<int> { 7, 8, 9 };
var combinedNumbers = numbers1.Concat(numbers2).Concat(numbers3);
在上述示例中,通过连续调用 Concat 方法连接了三个整数列表,结果得到了一个包含所有元素的新集合 combinedNumbers。
总结来说,Concat 方法是用于将两个或多个集合连接在一起的 LINQ 方法。它返回一个新的集合,保留了原始集合中的所有元素。
Zip
在 LINQ 中,Zip 方法用于将两个集合(或序列)按索引位置一对一地组合在一起,并返回一个新的集合。 Zip 方法对两个集合中的对应元素进行一对一的配对,并返回一个新的集合,其中每个元素都是由两个集合对应位置的元素组成的。
Zip 方法的语法如下:
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
参数:
first:表示第一个集合。
second:表示第二个集合。
resultSelector:表示一个函数,用于指定如何将两个集合中的对应元素进行组合,并生成新元素。这个函数接受两个参数,分别代表第一个集合和第二个集合中对应索引位置的元素,返回生成的新元素。
返回值:
返回一个实现 IEnumerable 接口的对象,其中包含了两个集合按索引位置组合后的结果集合。
下面是一个更详细的 Zip 方法解析的示例:
var numbers1 = new List<int> { 1, 2, 3 };
var numbers2 = new List<int> { 4, 5, 6 };
var combinedNumbers = numbers1.Zip(numbers2, (n1, n2) => n1 + n2);
foreach (var number in combinedNumbers)
{
Console.WriteLine(number);
}
输出结果为:
5
7
9
在上述示例中,Zip 方法将两个整数列表 numbers1 和 numbers2 按索引位置一对一地组合在一起。通过提供一个 lambda 表达式作为 resultSelector 参数,将对应索引位置的元素相加,生成一个新的元素。最终得到一个新的集合 combinedNumbers,包含了两个集合按索引位置组合后的结果。
需要注意的是,Zip 方法仅考虑两个集合中较短的那个集合的元素数量,如果两个集合的数量不一致,那么结果集合的大小将等于较短集合的元素数量。多余的元素将被忽略。
此外,Zip 方法还可以使用更复杂的逻辑来组合元素。只需要根据需要编写适当的 resultSelector 函数来生成新元素即可。
Distinct
在 LINQ 中,Distinct 方法用于从集合中筛选出唯一的元素,去除重复的元素。Distinct 方法会返回一个新的集合,其中包含原始集合中不重复的元素。
Distinct 方法的语法如下:
public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source)
参数:
source:表示要筛选唯一元素的源集合。
返回值:
返回一个实现 IEnumerable 接口的对象,其中包含了源集合中的唯一元素。
下面是一个更详细的 Distinct 方法解析的示例:
var numbers = new List<int> { 1, 2, 2, 3, 3, 4, 5, 5 };
var uniqueNumbers = numbers.Distinct();
foreach (var number in uniqueNumbers)
{
Console.WriteLine(number);
}
输出结果为:
1
2
3
4
5
在上述示例中,Distinct 方法将整数列表 numbers 中的重复元素去除,只保留唯一的元素。得到新的集合 uniqueNumbers,其中包含了不重复的元素。通过 foreach 循环遍历 uniqueNumbers,逐个输出唯一的元素。
Except
在 LINQ 中,Except 方法用于从一个集合中排除另一个集合中的元素,并返回一个包含仅存在于第一个集合中的元素的新集合。Except 方法会去除重复的元素,并且只保留在第一个集合中出现的元素。
Except 方法的语法如下:
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
参数:
first:表示第一个集合,从中排除元素。
second:表示第二个集合,要排除的元素将根据这个集合进行过滤。
返回值:
返回一个实现 IEnumerable 接口的对象,其中包含了在第一个集合中但不在第二个集合中出现的元素。
下面是一个更详细的 Except 方法解析的示例:
var numbers1 = new List<int> { 1, 2, 3, 4, 5 };
var numbers2 = new List<int> { 4, 5, 6 };
var uniqueNumbers = numbers1.Except(numbers2);
foreach (var number in uniqueNumbers)
{
Console.WriteLine(number);
}
输出结果为:
1
2
3
在上述示例中,Except 方法将整数列表 numbers1 中存在于 numbers2 中的元素排除,只保留在 numbers1 中独有的元素。得到新的集合 uniqueNumbers,其中包含了在 numbers1 中但不在 numbers2 中出现的元素。通过 foreach 循环遍历 uniqueNumbers,逐个输出排除后的元素。
需要注意的是,Except 方法默认会使用元素的默认相等比较器来判断元素是否相同。如果希望自定义比较操作,可以通过重载的 Except 方法或自定义相等比较器进行操作。例如:
var employees1 = new List<Employee>
{
new Employee { Id = 1, Name = "John" },
new Employee { Id = 2, Name = "Alice" }
};
var employees2 = new List<Employee>
{
new Employee { Id = 2, Name = "Alice" },
new Employee { Id = 3, Name = "Bob" }
};
var uniqueEmployees = employees1.Except(employees2, new EmployeeComparer());
foreach (var employee in uniqueEmployees)
{
Console.WriteLine($"Id: {employee.Id}, Name: {employee.Name}");
}
在上述示例中,我们有两个包含员工对象的列表 employees1 和 employees2。我们提供了自定义的 EmployeeComparer 类来实现根据员工的特定字段(例如 Id 或 Name)进行比较,并使用它进行排除操作。
Reverse
在 LINQ 中,Reverse 方法用于翻转集合中元素的顺序,并返回一个新的集合。它会返回与原始集合中的元素相反顺序的新集合。
Reverse 方法的语法如下:
public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source)
参数:
source:表示要进行翻转操作的原始集合。
返回值:
返回一个实现 IEnumerable 接口的对象,其中包含了与原始集合的元素相反顺序的元素。
下面是一个更详细的 Reverse 方法解析的示例:
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var reversedNumbers = numbers.Reverse();
foreach (var number in reversedNumbers)
{
Console.WriteLine(number);
}
输出结果为:
5
4
3
2
1
在上述示例中,我们有一个整数列表 numbers。我们使用 Reverse 方法将列表中元素的顺序翻转,并将结果赋给 reversedNumbers 变量。然后,通过 foreach 循环遍历 reversedNumbers,逐个输出翻转后的元素。
需要注意的是,Reverse 方法会创建并返回一个新的集合,而不会修改原始集合。所以,在使用 Reverse 方法后,原始集合的顺序仍然保持不变。
SequenceEqual
SequenceEqual 是 LINQ 提供的一个方法,用于比较两个序列是否相等。它用于检查两个序列中的元素是否完全相同,且以相同的顺序出现。如果序列中的元素类型是引用类型,请确保它们实现了适当的相等比较。
SequenceEqual 方法的语法如下:
bool result = sequence1.SequenceEqual(sequence2);
其中,sequence1 和 sequence2 是要比较的两个序列。方法将返回一个布尔值,指示两个序列是否完全相等。
下面是一个使用 SequenceEqual 方法比较两个整型序列的示例:
int[] sequence1 = { 1, 2, 3, 4, 5 };
int[] sequence2 = { 1, 2, 3, 4, 5 };
bool result = sequence1.SequenceEqual(sequence2);
Console.WriteLine(result); // 输出:True
在这个例子中,sequence1 和 sequence2 中的元素都是相同的,并且以相同的顺序出现,因此 SequenceEqual 方法返回 true。
ToLookup
ToLookup 是 LINQ 提供的一个方法,用于将一个序列转换为一个键值对集合,其中键是根据指定的键选择器从元素中提取的,而值是具有指定元素类型的元素的序列。它类似于 GroupBy,但有一些重要的区别。
ToLookup 方法的语法如下:
ILookup<TKey, TElement> lookup = source.ToLookup(keySelector);
其中,source 是要转换为键值对集合的源序列,keySelector 是一个函数,用于从每个元素中提取用作键的值。方法调用将返回一个实现 ILookup
下面是一个使用 ToLookup 方法的示例:
class Student
{
public string Name { get; set; }
public string Grade { get; set; }
}
List<Student> students = new List<Student>
{
new Student { Name = "John", Grade = "A" },
new Student { Name = "Jane", Grade = "B" },
new Student { Name = "Bob", Grade = "A" },
new Student { Name = "Alice", Grade = "C" },
new Student { Name = "Tom", Grade = "B" }
};
ILookup<string, Student> gradeLookup = students.ToLookup(s => s.Grade);
foreach (var group in gradeLookup)
{
Console.WriteLine("Grade: " + group.Key);
foreach (var student in group)
{
Console.WriteLine("- " + student.Name);
}
Console.WriteLine();
}
在这个例子中,我们有一个包含学生对象的列表。我们使用 ToLookup 方法将学生对象按照成绩(Grade)进行分组,并创建一个键值对集合。键是学生的成绩,而值是具有相同成绩的学生序列。
然后,我们遍历键值对集合,打印每个成绩分组中的学生姓名。
输出将是:
Grade: A
- John
- Bob
Grade: B
- Jane
- Tom
Grade: C
- Alice
ToLookup 方法适用于需要按键分组并在需要时通过键访问特定分组的情况。与 GroupBy 不同,ToLookup 返回的结果可以像字典一样通过键来访问,即使没有元素的分组也会返回一个空序列。
OfType
OfType 是 LINQ 提供的一个方法,用于筛选出指定类型的元素,而忽略其他类型的元素。它对于过滤序列中的特定类型的元素非常有用。
OfType 方法的语法如下:
IEnumerable<TResult> result = source.OfType<TResult>();
其中,source 是要筛选的源序列,TResult 是你想要选择的类型。方法调用将返回一个 IEnumerable,其中包含源序列中的符合指定类型的元素。
下面是一个使用 OfType 方法的示例:
object[] values = { "John", 30, "Jane", true, 10.5 };
var strings = values.OfType<string>();
foreach (var str in strings)
{
Console.WriteLine(str);
}
在这个例子中,我们有一个包含不同类型的对象数组。我们使用 OfType 方法来筛选出其中的字符串类型元素。最终,我们遍历结果序列,并打印出所有的字符串值。
输出将是:
John
Jane
只有字符串类型的元素被筛选出来,而其他类型的元素被忽略。
OfType 方法对于从混合类型的序列中选择特定类型的元素很有用。它过滤掉了不符合指定类型的元素,并返回一个仅包含特定类型元素的序列。
请注意,OfType 方法只会返回与指定类型完全匹配的元素,并不会执行任何隐式转换。
Cast
在 LINQ 中,Cast 方法用于在泛型集合中进行类型转换操作。它将集合中的元素按照指定的类型进行转换,并返回一个新的集合。
Cast 方法的语法如下:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source);
参数:
source:要进行类型转换的原始集合。
返回值:
一个新的 IEnumerable 对象,其中包含了转换后的元素。
下面是一个使用 Cast 方法的示例:
ArrayList list = new ArrayList();
list.Add(1);
list.Add(2);
list.Add(3);
IEnumerable<int> numbers = list.Cast<int>();
foreach (var number in numbers)
{
Console.WriteLine(number);
}
输出结果为:
1
2
3
在上述示例中,我们有一个非泛型集合 ArrayList,其中包含了整数类型的元素。我们使用 Cast 方法将该集合转换为一个泛型集合 IEnumerable,并将结果赋给 numbers 变量。然后,通过 foreach 循环遍历 numbers,逐个输出转换后的整数元素。
需要注意的是,Cast 方法只能对具有有效转换的元素进行类型转换。如果原始集合中的元素类型与目标类型不兼容,则会抛出异常。因此,在使用 Cast 方法之前,需要确保原始集合中的元素类型可以转换为目标类型。
另外,如果原始集合已经是泛型集合,即已经是指定类型的集合,那么 Cast 方法将直接返回原始集合,而不进行任何类型转换。
总结来说,Cast 方法用于在泛型集合中对元素进行类型转换。它将原始集合中的元素按照指定的类型进行转换,并返回一个新的集合。需要确保原始集合中的元素类型可以转换为目标类型。
Range
在 LINQ 中,Range 方法用于生成一个由连续整数构成的序列。该序列包括一个起始值和一个结束值,并按照指定的步长递增。Range 方法返回一个 IEnumerable 对象,该对象表示生成的整数序列。
Range 方法有一个重载形式:
public static IEnumerable<int> Range(int start, int count);
参数:
start:序列的起始值。
count:要生成的整数的数量。
返回值:
返回一个包含生成的整数序列的 IEnumerable 对象。
下面是一个使用 Range 方法的示例:
IEnumerable<int> numbers = Enumerable.Range(1, 5);
foreach (int number in numbers)
{
Console.WriteLine(number);
}
输出结果为:
1
2
3
4
5
在上述示例中,我们使用 Range 方法生成一个由 1 到 5 的整数序列。起始值为 1,生成的整数数量为 5。生成的整数序列分别为 1、2、3、4、5。然后,我们通过 foreach 循环遍历这个序列,并逐个输出其中的整数元素。
需要注意的是,序列的起始值和数量参数必须是非负整数。如果提供的数量为负数,则会抛出异常。
Repeat
在 LINQ 中,Repeat 方法用于生成一个包含重复元素的序列。它返回一个 IEnumerable 对象,该对象表示包含指定元素重复的序列。
Repeat 方法有一个重载形式:
public static IEnumerable<T> Repeat<T>(T element, int count);
参数:
element:要重复的元素。
count:要生成的重复元素的数量。
返回值:
返回一个包含重复元素的 IEnumerable 对象。
下面是一个使用 Repeat 方法的示例:
IEnumerable<string> repeated = Enumerable.Repeat("Hello", 3);
foreach (string item in repeated)
{
Console.WriteLine(item);
}
输出结果为:
Hello
Hello
Hello
在上述示例中,我们使用 Repeat 方法生成一个包含三个重复的字符串元素 “Hello” 的序列。我们指定要重复的元素为 “Hello”,要生成的重复元素的数量为 3。生成的序列中包含三个 “Hello” 元素。然后,我们通过 foreach 循环遍历这个序列,并逐个输出其中的元素。
需要注意的是,生成的序列中的元素都是相同的。如果提供的数量为非正数(小于等于0),则生成的序列为空序列。
Prepend
在 LINQ 中,Prepend 方法用于在序列的开头添加一个元素,生成一个新的序列。它返回一个包含原始序列中所有元素以及指定元素的新序列。
Prepend 方法有一个重载形式。
重载形式如下:
public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource element);
该重载形式用于在序列的开头添加一个元素。
参数:
source:要在其开头添加元素的源序列。
element:要添加到序列开头的元素。
返回值:
返回一个包含原始序列中所有元素以及指定元素的新序列。
下面是使用 Prepend 方法的示例:
int[] numbers = { 2, 3, 4, 5 };
IEnumerable<int> newNumbers = numbers.Prepend(1);
foreach (int number in newNumbers)
{
Console.WriteLine(number);
}
在上述示例中,我们定义了一个整数数组 numbers,其中包含 4 个元素。然后,我们使用 Prepend 方法在数组开头添加元素 1,生成一个新的序列。我们将新序列赋值给变量 newNumbers,并通过 foreach 循环遍历新序列,将每个元素打印到控制台。输出结果为:
1
2
3
4
5
注意,Prepend 方法不会修改原始序列,而是生成一个新的序列,该新序列首先包含指定的元素,然后是原始序列的所有元素。