【问题标题】:Quickest way to search for objects in a very large list by string C#通过字符串 C# 在非常大的列表中搜索对象的最快方法
【发布时间】:2019-03-04 05:09:56
【问题描述】:

例如我有一个像下面这样的类:

public class MasterRecord
{
     public int Id { get; set; }
     public string UniqueId{ get; set; }
}

public class DetailRecord
{
     public int Id { get; set; }

     public int MasterRecordId { get; set; }

     public string UniqueId{ get; set; }
}

我还列出了 2 个列表:

MasterList 和 DetailList

MasterList 将有大约 300,000 条记录, DetailList 将有大约 7,000,000 条记录

我需要的是循环主列表中的每条记录,并在详细列表中搜索具有相同名称的记录。

这是我的代码:

 foreach (var item in MasterList)
 {
    var matchPersons = DetailList.Where(q => q.UniqueId == item .UniqueId).ToList();

    if (matchPersons != null && matchPersons.Count() > 0)
    {
        foreach (var foundPerson in matchPersons)
        {
            //Do something with foundPerson
            foundPerson.MasterRecordId = item.Id;
        }
    }
 }

我的代码现在运行很慢,每次搜索花费我 500 毫秒才能完成,所以如果有 300k 条记录,则需要 2500 分钟 :( 才能完成。 有没有其他方法可以加快这个功能? 感谢并原谅我糟糕的英语。

更新的代码让我更清楚我想要做什么。

【问题讨论】:

  • 您的列表是否来自数据库?
  • 创建一个字典,这将花费时间,但在进行多次搜索时同样显着。 Dictionary dict1 = MasterList .GroupBy(x => x.Name, y => y) .​​ToDictionary(x => x.Key, y => y.FirstOrDefault());或者,如果您有多个同名的人 Dictionary> dict2 = MasterList .GroupBy(x => x.Name, y => y) .​​ToDictionary(x => x.Key, y => y .ToList());

标签: c# linq search


【解决方案1】:

使用一些哈希结构将是最好的选择之一:

var detailLookup = DetailList.ToLookup(q => q.Name);
foreach (var person in MasterList)
{
    foreach (var foundPerson in detailLookup[person.Name])
    {
        //Do something with foundPerson                
    }
}

如果键不存在,查找返回空序列,因此您不必对其进行测试。

【讨论】:

    【解决方案2】:

    您可以在名称上使用联接。

    var result = masterList.Join(detailedList,m=>m.Name,d=>d.Name,(m,d)=>d);
    

    【讨论】:

      【解决方案3】:

      如果您需要处理“MasterRecords 及其 DetailRecords”,请不要使用普通连接,请使用 GroupJoin。这将在内部创建类似于 LookupTable 的东西。

      好消息是这也适用于数据库、CSV 文件或您用来获取记录的任何方法。您不必先将它们转换为列表。

      // Your input sequences, if desired: use IQueryable
      IEnumerable<MasterRecord> masterRecords = ...
      IEnumerable<DetailRecord> detailRecords = ...
      // Note: query not executed yet!
      
      // GroupJoin these two sequences
      var masterRecordsWithTheirDetailRecords = masterRecord.GroupJoin(detailRecords,
          masterRecord => masterRecord.Id,             // from masterRecord take the primary key
          detailRecord => detailRecord.MasterRecordId  // from detailRecord take the foreign key
      
          // ResultSelector: from every MasterRecord with its matching DetailRecords select
          (masterRecord, detailRecords) => new
          {
              // select the properties you plan to use:
              Id = masterRecord.Id,
              UniqueId = maserRecord.UniqueId,
              ...
      
              DetailRecords = detailRecords.Select(detailRecord => new
              {
                  // again: select only the properties you plan to use
                  Id = detailRecord.Id,
                  ...
      
                  // not needed, you know the value:
                  // MasterRecordId = detailRecord.MasterRecordId,
              }),
              // Note: this is still an IEnumerable!            
           });
      

      用法:

      foreach(var masterRecord in masterRecordsWithTheirDetailRecords)
      {
          ... // process the master record with its detail records
      }
      

      好消息是,您只需要处理一些 MasterRecords (例如,在第 1000 个之后,您决定找到您搜索的内容), 或者,如果您有一些不需要所有 DetailRecord 的 MasterRecord,则不会处理不必要的记录。 Linq 会解决这个问题

      【讨论】:

      • 感谢您的帮助,但就我而言,我有 2 个表已经从另一个数据库导入。但由于某种原因,当时我无法在明细表中拥有外键。所以我需要运行这个函数来通过 Unique-id 字段将 Master & Detail 表映射在一起。所以不确定您的解决方案是否会有所帮助。
      猜你喜欢
      • 2016-10-08
      • 1970-01-01
      • 2018-10-13
      • 2017-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-24
      相关资源
      最近更新 更多