我有两个自定义对象列表,如果另一个列表中的某个对象与另一对字段匹配,则需要更新一个列表中所有对象的字段。
此代码更好地解释了问题,并产生了我想要的结果。但是对于较大的列表20k和具有匹配对象的20k列表,这需要相当长的时间(31秒)。通过使用通用列表Find(Predicate)方法,我可以使用~50%来改善这一点。
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
namespace ExperimentFW3
{
public class PropValue
{
public string Name;
public decimal Val;
public decimal Total;
}
public class Adjustment
{
public string PropName;
public decimal AdjVal;
}
class Program
{
static List<PropValue> propList;
static List<Adjustment> adjList;
public static void Main()
{
propList = new List<PropValue>{
new PropValue{Name = "Alfa", Val=2.1M},
new PropValue{Name = "Beta", Val=1.0M},
new PropValue{Name = "Gamma", Val=8.0M}
};
adjList = new List<Adjustment>{
new Adjustment{PropName = "Alfa", AdjVal=-0.1M},
new Adjustment{PropName = "Beta", AdjVal=3M}
};
foreach (var p in propList)
{
Adjustment a = adjList.SingleOrDefault(
av => av.PropName.Equals(p.Name)
);
if (a != null)
p.Total = p.Val + a.AdjVal;
else
p.Total = p.Val;
}
}
}
}
期望的结果是:Alfa total = 2,Beta total = 4,Gamma total = 8
但我想知道这是否有可能做得更快。即使在结果集中循环超过20k项时,内部连接两个列表也只需要很少的时间。
var joined = from p in propList
join a in adjList on p.Name equals a.PropName
select new { p.Name, p.Val, p.Total, a.AdjVal };
所以我的问题是,是否有可能像我对T-SQL那样做一些事情?来自左连接的UPDATE,使用ISNULL(val,0)调整值。
答案 0 :(得分:6)
该连接应该相当快,因为它将首先遍历所有adjList
以创建查找,然后对于propList
中的每个元素,它将仅使用查找。这比较大的代码中的O(N * M)方法要快 - 尽管可以通过adjList
调用ToLookup
(或ToDictionary
,因为您只需要一个值)来轻松修复在循环之前。
编辑:这是使用ToDictionary
的修改后的代码。未经考验,请注意......
var adjDictionary = adjList.ToDictionary(av => av.PropName);
foreach (var p in propList)
{
Adjustment a;
if (adjDictionary.TryGetValue(p.Name, out a))
{
p.Total = p.Val + a.AdjVal;
}
else
{
p.Total = p.Val;
}
}
答案 1 :(得分:0)
如果adjList可能具有重复的名称,则应在推送到字典之前对项目进行分组。
Dictionary<string, decimal> adjDictionary = adjList
.GroupBy(a => a.PropName)
.ToDictionary(g => g.Key, g => g.Sum(a => a.AdjVal))
propList.ForEach(p =>
{
decimal a;
adjDictionary.TryGetValue(p.Name, out a);
p.Total = p.Val + a;
});
答案 2 :(得分:0)
我知道我迟到了这个,但我想有人会欣赏下面更清晰的简短答案,它在adjList中处理每个查询的多个记录。创建LookUp将允许快速查找多个项目,如果LookUp中没有记录,则会返回一个空列表。
var adjLookUp = adjList.ToLookUp(a => a.PropName);
foreach (var p in propList)
p.Total = p.Val + adjLookUp[p.Name].Sum(a => a.AdjVal);