四、元素添加与计数

用于扩展序列统计元素数量。这类操作在处理集合数据时非常常见,合理使用可以高效地操作和分析序列。

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)

性能优化建议

  1. 优先使用 TryGetNonEnumeratedCount:对于已知集合类型(如 List<T>),避免重复枚举。
  2. 避免频繁调用 Count():在循环中多次调用 Count() 会导致性能问题,建议缓存结果。
  3. 大数据集使用 LongCount():防止 int 溢出。
  4. 使用 HashSet<T> 优化包含检查:如果需要频繁检查元素是否存在,先将集合转换为 HashSet<T>
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐