The*_*heo 4 c# linq algorithm collections performance
我正在从另一个数据库导入数据。
我的过程是将数据从远程数据库导入到List<DataModel>命名的数据库中,并将remoteData数据从本地数据库导入到List<DataModel>命名的localData.
然后我使用 LINQ 创建一个不同的记录列表,以便我可以更新本地数据库以匹配从远程数据库中提取的数据。像这样:
var outdatedData = this.localData.Intersect(this.remoteData, new OutdatedDataComparer()).ToList();
Run Code Online (Sandbox Code Playgroud)
然后我使用 LINQ 创建一个不再存在于remoteData中但确实存在于中的记录列表localData,以便我将它们从本地数据库中删除。
像这样:
var oldData = this.localData.Except(this.remoteData, new MatchingDataComparer()).ToList();
Run Code Online (Sandbox Code Playgroud)
然后我使用 LINQ 执行与上述相反的操作,将新数据添加到本地数据库。
像这样:
var newData = this.remoteData.Except(this.localData, new MatchingDataComparer()).ToList();
Run Code Online (Sandbox Code Playgroud)
每个集合导入大约 70k 条记录,3 个 LINQ 操作中的每一个都需要 5 到 10 分钟才能完成。我怎样才能更快?
这是集合正在使用的对象:
internal class DataModel
{
public string Key1{ get; set; }
public string Key2{ get; set; }
public string Value1{ get; set; }
public string Value2{ get; set; }
public byte? Value3{ get; set; }
}
Run Code Online (Sandbox Code Playgroud)
用于检查过时记录的比较器:
class OutdatedDataComparer : IEqualityComparer<DataModel>
{
public bool Equals(DataModel x, DataModel y)
{
var e =
string.Equals(x.Key1, y.Key1) &&
string.Equals(x.Key2, y.Key2) && (
!string.Equals(x.Value1, y.Value1) ||
!string.Equals(x.Value2, y.Value2) ||
x.Value3 != y.Value3
);
return e;
}
public int GetHashCode(DataModel obj)
{
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
用于查找新旧记录的比较器:
internal class MatchingDataComparer : IEqualityComparer<DataModel>
{
public bool Equals(DataModel x, DataModel y)
{
return string.Equals(x.Key1, y.Key1) && string.Equals(x.Key2, y.Key2);
}
public int GetHashCode(DataModel obj)
{
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
通过使用恒定的哈希码,您已经破坏了性能。这是 Intersect 使用的内部代码(通过反编译器获得)
public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
if (first == null)
{
throw Error.ArgumentNull("first");
}
if (second == null)
{
throw Error.ArgumentNull("second");
}
return Enumerable.IntersectIterator<TSource>(first, second, comparer);
}
private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource current in second)
{
set.Add(current);
}
foreach (TSource current2 in first)
{
if (set.Remove(current2))
{
yield return current2;
}
}
yield break;
}
Run Code Online (Sandbox Code Playgroud)
看到它在Set内部使用,如果你实现了哈希码将大大提高它的性能。
MatchingDataCompaer 是两者中更容易的,所以我会为你做那个。
internal class MatchingDataComparer : IEqualityComparer<DataModel>
{
public MatchingDataComparer()
{
comparer = StringComparer.Ordnal; //Use whatever comparer you want.
}
private readonly StringComparer comparer;
public bool Equals(DataModel x, DataModel y)
{
return comparer.Equals(x.Key1, y.Key1) && comparer.Equals(x.Key2, y.Key2);
}
//Based off of the advice from http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
public int GetHashCode(DataModel obj)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 23 + comparer.GetHashCode(obj.Key1);
hash = hash * 23 + comparer.GetHashCode(obj.Key2);
return hash;
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可能会使用MatchingDataComparerin 中的 hashcode 函数OutdatedDataComparer,它可能不是“最佳”哈希码1,但它将是“合法” 2,并且比硬编码 0 快得多。
1. 或者可能是,我不确定我将如何包含第三个&&条件
2. 如果a.Equals(b) == true那么a.GetHashCode() == b.GetHashCode().
如果a.Equals(b) == false那么a.GetHashCode() == b.GetHashCode() || a.GetHashCode() != b.GetHashCode()
| 归档时间: |
|
| 查看次数: |
2910 次 |
| 最近记录: |