我需要在比较和操纵其值时优化代码。我有两个数据集合,比如集合A和集合B.在集合A中是所有现有数据的列表,在集合B中是合并现有数据和要添加的新数据。现在,我需要检查集合B中是否存在集合B,如果存在,我需要使用集合B的更新数据设置或修改集合A的特定数据。如果集合B的特定数据在A中不存在则我需要将它添加到集合A中。
这是我的代码。
public CollectionA Save(List<CollectionB> collectionb)
var collectionA = collectionA.GetAll().OrderByDescending(x => x.SortOrder);
foreach (var b in collectionb)
{
if (b.Id == 0)
{
a.Add(b);
continue;
}
foreach (var a in collectionA.Where(aa => aa.Id == b.Id))
{
a.ZoneCode = b.ZoneCode;
a.SortOrder = b.SortOrder;
a.Point1 = b.Point1;
a.Point2 = b.Point2;
a.Point3 = b.Point3;
a.RangeSpread = b.RangeSpread;
a.MidpointDifferential = b.MidpointDifferential;
a.AnnualIncentivePercent = b.AnnualIncentivePercent;
a.AnnualIncentiveAmount = b.AnnualIncentiveAmount;
a.GradeMisc1 = b.GradeMisc1;
a.GradeMisc2 = b.GradeMisc2;
a.ZoneComment = b.ZoneComment;
}
}
答案 0 :(得分:1)
所以你有2个大型列表,你想找到它们之间的变化,而不是真正地将每个人与每个人进行比较。
您应该创建2个词典并按其键值对其进行索引。 C#匿名类型非常适合这种情况,因为编译器已根据值生成GetHashCode和Equals。
这是一种相当天真的方法(因为它可以轻松抛出OutOfMemoryException,因为它可以完成内存中的所有操作),但它应该比仅仅比较A中的所有内容和B中的所有内容更好地执行更多。 这只会比较密钥相同的值:
class ListComparisonResult<TKey>
{
public IList<TKey> NewKeys { get; private set; }
public IList<TKey> OldKeys { get; private set; }
public IList<TKey> ChangedKeys { get; private set; }
public ListComparisonResult(IList<TKey> newKeys, IList<TKey> oldKeys, IList<TKey> changedKeys)
{
NewKeys = new ReadOnlyCollection<TKey>(newKeys);
OldKeys = new ReadOnlyCollection<TKey>(oldKeys);
ChangedKeys = new ReadOnlyCollection<TKey>(changedKeys);
}
}
ListComparisonResult<TKey> GetChanges<TRow, TKey, TValues>(
IEnumerable<TRow> collectionA,
IEnumerable<TRow> collectionB,
Func<TRow, TKey> keySelector,
Func<TRow, TValues> comparableValuesSelector)
{
var byId = new
{
A = collectionA.ToDictionary(keySelector),
B = collectionB.ToDictionary(keySelector),
};
var sameIds = new HashSet<TKey>(byId.A.Keys.Where(byId.B.ContainsKey));
var changedIds = (from id in sameIds
let a = byId.A[id]
let b = byId.B[id]
where !comparableValuesSelector(a).Equals(comparableValuesSelector(b))
select id).ToList();
var oldIds = byId.A.Keys.Where(id => !byId.B.ContainsKey(id)).ToList();
var newIds = byId.B.Keys.Where(id => !byId.A.ContainsKey(id)).ToList();
return new ListComparisonResult<TKey>(newIds, oldIds, changedIds);
}
这是如何使用的:
var r = new Random();
var collectionA = (from id in Enumerable.Range(0, 1000000)
select new
{
ID = id,
Value1 = r.Next(1, 3),
Value2 = r.Next(0, 1) == 1,
}).ToList();
var collectionB = (from id in Enumerable.Range(58945, 1000000)
select new
{
ID = id,
Value1 = r.Next(1, 3),
Value2 = r.Next(0, 1) == 1,
}).ToList();
var timer = Stopwatch.StartNew();
var changes = GetChanges(collectionA, collectionB, t => t.ID, t => new{t.Value1, t.Value2});
timer.Stop();
Console.WriteLine(new
{
changedIds = changes.ChangedKeys.Count,
newIds = changes.NewKeys.Count,
oldIds = changes.OldKeys.Count,
timer.ElapsedMilliseconds
});
答案 1 :(得分:0)
使用.FirstOrDefault方法查找具有相同ID的项目。如果该项目存在,请将其从主集合中删除,然后添加新(/更新)项目。如果没有匹配的ID,只需添加新项。
foreach (var b in collectionB)
{
var itemToUpdate = collectionA.FirstOrDefault(a => a.Id == b.Id);
if (itemToUpdate != null)
{
collectionA.Remove(itemToUpdate);
}
collectionA.Add(b);
}
编辑:
如果您的列表包含具有唯一ID的项目,则可以使用.SingleOrDefault方法。不同的是,如果有多个具有相同ID的项目,.SingleOrDefault将抛出异常。