【实战】提升List性能方法有几何

在内存中的 List<T> 上使用 LINQ 查询时,加索引并不像数据库那样有内置支持,但可以通过以下方式提高查询性能:


1. 手动构建索引

可以手动构建一个字典 (Dictionary<TKey, TValue>),将需要查询的字段作为键,值为对应的数据。查询时直接利用字典的 O(1) 查找性能。

示例代码:
csharp 复制代码
// 假设有一个类
public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// 构建索引
var employees = new List<Employee>
{
    new Employee { Id = 1, Name = "Alice" },
    new Employee { Id = 2, Name = "Bob" },
    new Employee { Id = 3, Name = "Charlie" }
};

// 创建索引
var employeeIndex = employees.ToDictionary(e => e.Id, e => e);

// 查询时使用索引
int searchId = 2;
if (employeeIndex.TryGetValue(searchId, out var employee))
{
    Console.WriteLine($"Found: {employee.Name}");
}
else
{
    Console.WriteLine("Not Found");
}

2. 预先分组以提高查询性能

对于需要多次按某个字段查询的场景,可以使用 Lookup<TKey, TElement> 预分组数据。Lookup 类似于 Dictionary,但支持一个键对应多个值。

示例代码:
csharp 复制代码
// 构建分组索引
var employeeLookup = employees.ToLookup(e => e.Name);

// 按 Name 查询
string searchName = "Alice";
foreach (var emp in employeeLookup[searchName])
{
    Console.WriteLine($"Found: {emp.Name} with Id: {emp.Id}");
}

3. 自定义数据结构

如果查询条件多样化,可以构建多字段索引,类似于复合索引。

示例代码:
csharp 复制代码
// 复合索引
var compositeIndex = employees.ToDictionary(e => (e.Id, e.Name), e => e);

// 查询
var key = (Id: 1, Name: "Alice");
if (compositeIndex.TryGetValue(key, out var result))
{
    Console.WriteLine($"Found: {result.Name}");
}

4. 排序后使用二分查找

如果 List<T> 是按查询字段排序的,可以使用 BinarySearch 来快速查找。

示例代码:
csharp 复制代码
// 排序列表
employees = employees.OrderBy(e => e.Id).ToList();

// 二分查找
int searchId = 2;
var found = employees.BinarySearch(
    new Employee { Id = searchId },
    Comparer<Employee>.Create((x, y) => x.Id.CompareTo(y.Id))
);

if (found >= 0)
{
    Console.WriteLine($"Found: {employees[found].Name}");
}
else
{
    Console.WriteLine("Not Found");
}

5. 使用缓存优化查询

如果查询是频繁且集中在某些字段上,可以构建一个缓存层,例如使用 MemoryCache

示例代码:
csharp 复制代码
using System.Runtime.Caching;

// 创建缓存
var cache = MemoryCache.Default;
string cacheKey = "EmployeeById";
cache[cacheKey] = employeeIndex; // 使用之前构建的字典

// 查询缓存
if (cache.Contains(cacheKey))
{
    var cachedIndex = (Dictionary<int, Employee>)cache[cacheKey];
    if (cachedIndex.TryGetValue(2, out var cachedEmployee))
    {
        Console.WriteLine($"From Cache: {cachedEmployee.Name}");
    }
}

6. 结合并行查询

对于大规模数据,可以结合并行 LINQ (PLINQ) 提高查询速度。

示例代码:
csharp 复制代码
// 使用 PLINQ
var result = employees.AsParallel()
    .Where(e => e.Name.StartsWith("A"))
    .ToList();

foreach (var emp in result)
{
    Console.WriteLine($"Found: {emp.Name}");
}

总结

加索引的方法需要根据具体场景选择:

  • 如果查询频繁,使用 DictionaryLookup
  • 如果是多字段组合查询,构建复合索引。
  • 如果数据较多且一次性查询,考虑使用排序加二分查找。
  • 对于性能要求极高的场景,可以结合缓存或并行查询优化。

根据你的需求,可以选用其中一个或多个组合方式。

相关推荐
在下小孙6 小时前
初始C#.
开发语言·c#
Nita.12 小时前
适配器模式详解:解决接口不兼容问题的灵活设计模式
设计模式·c#·适配器模式
Marzlam12 小时前
C# 多线程发展史(面试思路)
c#
步、步、为营13 小时前
C# 条件编译的应用
开发语言·c#
CodeCraft Studio13 小时前
如何利用.NET版PDF处理控件Aspose.PDF,使用 C# 从 PDF 中删除水印
pdf·c#·.net
pchmi13 小时前
C# OpenCV机器视觉:特征匹配 “灵魂伴侣”
人工智能·opencv·计算机视觉·c#·特征匹配·opencvsharp
飞由于度13 小时前
C#中无法在串口serialPort1_DataReceived启动定时器的解决方法
开发语言·c#
小乖兽技术13 小时前
模块化架构与微服务架构,哪种更适合桌面软件开发?
微服务·架构·c#
m0_7482404413 小时前
大屏开源项目go-view二次开发1----环境搭建(C#)
golang·开源·c#
山猪打不过家猪15 小时前
Azure面试
microsoft·azure