在 .NET 9 中,微软为 LINQ(Language Integrated Query)引入了三个新的扩展方法,增强了数据查询的灵活性和表达力。这些方法分别是 Index
、CountBy
和 AggregateBy
,为处理集合数据提供了更便捷的方式。
扩展方法
1. Index
Index
方法为序列中的每个元素提供其索引值,返回一个 (int Index, TSource Value)
的元组序列。这在需要同时访问元素及其索引的场景中非常有用,相比传统的 Select((value, index) => ...)
,Index
提供了一种更直观的语法。
- • 签名:
public static IEnumerable<(int Index, TSource Value)> Index<TSource>(this IEnumerable<TSource> source);
- • 功能:
为每个元素生成一个包含索引(从 0 开始)和值的元组序列。 - • 示例:
var fruits = new List<string> { "Apple", "Banana", "Cherry" };
foreach (var item in fruits.Index())
{Console.WriteLine($"Index: {item.Index}, Fruit: {item.Value}");
}
输出:
Index: 0, Fruit: Apple
Index: 1, Fruit: Banana
Index: 2, Fruit: Cherry
2. CountBy
CountBy
方法根据指定的键选择器对序列元素进行分组,并返回一个键值对序列,其中键是分组的键,值是该组的元素计数。这类似于 GroupBy(...).Select(g => new { g.Key, Count = g.Count() })
,但更简洁高效。
- • 签名:
public static IEnumerable<KeyValuePair<TKey, int>> CountBy<TSource, TKey>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector);
- • 功能:
按键分组并统计每组的元素数量,返回KeyValuePair<TKey, int>
序列。 - • 示例:
var people = new List<Person>
{new Person("Steve", "Jobs"),new Person("Steve", "Carell"),new Person("Elon", "Musk")
};
foreach (var group in people.CountBy(p => p.FirstName))
{Console.WriteLine($"There are {group.Value} people with the name {group.Key}");
}
输出:
There are 2 people with the name Steve
There are 1 people with the name Elon
Person 类定义:
public record Person(string FirstName, string LastName);
- • 使用场景:
- • 统计集合中某属性值的出现次数,例如分析数据中各类别的频率。
- • 替代复杂的
GroupBy
和Count
组合,简化代码。
- • 注意事项:
- • 键选择器返回的
TKey
必须支持相等性比较(默认使用EqualityComparer<TKey>.Default
)。 - • 如果序列为空,返回空序列。
3. AggregateBy
AggregateBy
方法允许对按键分组的元素执行自定义聚合操作,返回一个键值对序列,其中键是分组的键,值是聚合结果。这是对 GroupBy(...).Select(g => new { g.Key, Aggregate = g.Aggregate(...) })
的优化,性能更高且代码更简洁。
- • 签名:
public static IEnumerable<KeyValuePair<TKey, TResult>> AggregateBy<TSource, TKey, TResult>(this IEnumerable<TSource> source,Func<TSource, TKey> keySelector,TResult seed,Func<TResult, TSource, TResult> accumulator);
- • 功能:
按键分组后,对每组元素应用累加器函数进行聚合,返回KeyValuePair<TKey, TResult>
序列。 - • 示例:统计每个月份的销售总额
var sales = new List<Sale>
{new Sale { Date = new DateTime(2023, 1, 1), Amount = 100 },new Sale { Amount = 150 },new Sale { Date = new DateTime(2023, 2, 1), Amount = 200 },new Sale { Amount = 100 }
};
var monthlyTotals = sales.AggregateBy(s => s.Date.Month,seed: 0m,(total: decimal, sale: s) => total + sale: s.Amount
);
foreach (var total in monthlyTotals)
{Console.WriteLine($"Month: { total.Key }, Total Sales: { total.Value }");
}
输出:
Month: 1, Total Sales: 250
Month: 2, Total Sales: 300
Sale 类定义:
public record Sale { get; set; }{ DateTime Date { get; set; }; decimal Amount;
};