C#Linq查询(四):元素添加与计数(纯干货)
·
四、元素添加与计数
用于扩展序列或统计元素数量。这类操作在处理集合数据时非常常见,合理使用可以高效地操作和分析序列。
1. Append(element) / Prepend(element)
在序列末尾 / 开头添加一个元素(返回新序列,不修改原序列)。这两个方法都不会改变原始集合,而是返回一个包含原元素和新添加元素的新序列。
性能特性:时间复杂度为 O (1),但返回的是延迟执行的新序列,实际遍历新序列时才会产生元素。
典型场景:需要在不修改原集合的前提下,临时扩展序列。
示例 1:基础用法
var numbers = new List<int> { 1, 2, 3 };
// 在末尾添加元素
var appended = numbers.Append(4); // 结果: {1, 2, 3, 4}
// 在开头添加元素
var prepended = numbers.Prepend(0); // 结果: {0, 1, 2, 3}
// 原集合未被修改
Console.WriteLine(string.Join(", ", numbers)); // 输出: 1, 2, 3
示例 2:链式操作
var result = numbers
.Prepend(-1)
.Append(4)
.Append(5);
Console.WriteLine(string.Join(", ", result)); // 输出: -1, 1, 2, 3, 4, 5
2. Count() / Count(predicate)
返回元素总数 / 满足条件的元素数。Count() 方法有两种重载形式:无参数形式返回序列中的元素总数,带谓词参数的形式返回满足特定条件的元素数量。
性能特性:
- 对于实现了
ICollection<T>接口的集合(如List<T>),Count()是 O (1) 操作。 - 对于其他可枚举类型,可能需要遍历整个序列,性能为 O (n)。
典型场景:统计集合大小或筛选特定元素的数量。
示例 1:基础数值统计
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 获取总数
int total = numbers.Count(); // 结果: 6
// 统计偶数数量
int evenCount = numbers.Count(x => x % 2 == 0); // 结果: 3
// 统计大于10的元素数量(没有则返回0)
int largeCount = numbers.Count(x => x > 10); // 结果: 0
示例 2:对象集合统计
public class Product {
public int Id { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
var products = new List<Product> {
new Product { Id = 1, Category = "电子", Price = 1999 },
new Product { Id = 2, Category = "服装", Price = 199 },
new Product { Id = 3, Category = "电子", Price = 2999 },
new Product { Id = 4, Category = "食品", Price = 99 }
};
// 统计电子产品数量
int electronicsCount = products.Count(p => p.Category == "电子"); // 结果: 2
// 统计价格超过1000的产品数量
int expensiveCount = products.Count(p => p.Price > 1000); // 结果: 2
3. LongCount()
同 Count,但返回 long 类型(适合大数据量,避免 int 溢出)。当处理可能包含超过 int.MaxValue 个元素的序列时,应使用此方法。
性能特性:与 Count() 类似,对于非 ICollection<T> 类型的序列,可能需要遍历整个序列。
典型场景:处理超大数据集时避免整数溢出。
示例:处理大数据集
// 假设有一个非常大的数据集
IEnumerable<long> largeSequence = Enumerable.Range(1, int.MaxValue).Select(i => (long)i);
// 使用 LongCount 避免溢出
long count = largeSequence.LongCount();
Console.WriteLine($"元素总数: {count}"); // 输出: 2147483647 (int.MaxValue)
4. TryGetNonEnumeratedCount(out int count)(.NET 6+)
尝试获取序列计数(若数据源支持,如 ICollection<T>),避免枚举开销。该方法直接返回集合的已知计数(如果有),而无需遍历序列。
性能特性:O (1) 时间复杂度(若数据源支持直接计数)。
典型场景:需要多次使用集合元素数量时,先调用此方法可避免重复枚举带来的性能损耗。
示例:高效获取集合大小
var list = new List<int> { 1, 2, 3, 4, 5 };
if (list.TryGetNonEnumeratedCount(out int count))
{
Console.WriteLine($"集合元素数量: {count}"); // 直接获取,无需遍历
}
else
{
// 对于不支持直接计数的序列(如通过 yield 返回的序列)
count = list.Count(); // 此时需要遍历序列
Console.WriteLine($"通过枚举获取的元素数量: {count}");
}
核心对比与注意事项
| 方法 | 作用 | 适用场景 | 性能特性 |
|---|---|---|---|
Append |
在序列末尾添加元素 | 需要扩展集合时 | O (1) 时间复杂度(返回新序列) |
Prepend |
在序列开头添加元素 | 需要在起始位置插入元素时 | O (1) 时间复杂度(返回新序列) |
Count() |
获取元素总数 | 统计集合大小 | O (1)(对 ICollection<T>)或 O (n) |
Count(predicate) |
统计满足条件的元素数 | 筛选并计数特定元素 | O(n) |
LongCount() |
获取元素总数(long 类型) |
处理超大数据集时 | O (1) 或 O (n) |
TryGetNonEnumeratedCount |
尝试直接获取计数 | 避免枚举开销时 | O (1)(若支持)或 O (n) |
性能优化建议
- 优先使用
TryGetNonEnumeratedCount:对于已知集合类型(如List<T>),避免重复枚举。 - 避免频繁调用
Count():在循环中多次调用Count()会导致性能问题,建议缓存结果。 - 大数据集使用
LongCount():防止int溢出。 - 使用
HashSet<T>优化包含检查:如果需要频繁检查元素是否存在,先将集合转换为HashSet<T>。
更多推荐
所有评论(0)