在foreach循环中填充对象的List属性

时间:2014-10-24 11:15:41

标签: c# dapper

我想知道填充对象中的对象列表是否可以比我运行时看到的更快。 我填写了CABCodes-&使用Dapper和.ToList();

进行简单查询的CABDetails列表

因此两个列表都在内存中,但foreach操作大约需要20秒。

CABCodes:~10,000个对象

CABDetails:~60,000个对象

List<CABCode> CABCodes = new List<CABCode>();
List<CABDetail> CABDetails = new List<CABDetail>();

public class CABCode {
    public int Sequence { get; set; }
    public string Code { get; set; }
    public int Group { get; set; }
    public List<CABDetail> Details { get; set; }
}
public class CABDetail {
    public int CABSequence { get; set; }
    public int Proptype { get; set; }
    public string Propvalue { get; set; }
}

foreach (var c in this.CABCodes) {
    c.Details = this.CABDetails.Where(x => x.CABSequence == c.Sequence).ToList();
}

是否有更有效的方法来实现这一目标?

2 个答案:

答案 0 :(得分:2)

你有O(M * N)算法时间。 下面的代码使它成为O(M + N),这很快:

var cabDetailsBySequence = CABDetails.ToLookup(d=>d.CABSequence);

foreach (var c in this.CABCodes) {
    c.Details = cabDetailsBySequence[c.Sequence].ToList();
}

更新: 我检查它在110ms下工作,有100个不同的序列码。

以下是测试设置:

CABCodes = Enumerable.Range(0, 10000).Select(i=>new CABCode{Sequence = i%100}).ToList();
CABDetails = Enumerable.Range(0, 60000).Select(i=>new CABDetail{CABSequence = i%100}).ToList();

更新2: 如果您不介意在不同的CABCode实例中引用相同的列表,那么您可以使它更快(20倍aprox),如果您并行执行它们会更快。这样它在我的8核系统上运行不到一毫秒:

var cabDetailListsBySequence = cabDetailsBySequence.ToDictionary(i=>i.Key, i=>i.ToList());

//  foreach (var c in this.CABCodes) {
//      c.Details = cabDetailListsBySequence[c.Sequence];
//  }   

this.CABCodes.AsParallel().ForAll(c=>c.Details = cabDetailListsBySequence[c.Sequence]);

答案 1 :(得分:0)

Linq并不总是像使用if / else语句编写自己的循环一样快。第二件事是,ToList()创建一个List的新实例,这也会降低你的性能。

此代码的性能如何:

foreach (var c in this.CABCodes) 
{
  var detailList = new List<CABDetail>();
  foreach(var d in CAPDetails)
  {
    if (d.CABSquence == c.Sequence)
    {
      detailList.Add(d);
    }
  }
  c.Details = detailList;
}

也许我在代码中犯了一些错误,因为我是在飞行中写的。