c# - 如何使用 DataTable 和 Linq 优化代码?
问题描述
我有 2 个数据表。大约有17000 (table1)和100000 (table2)记录。
需要检查“FooName”字段是否包含“ItemName”。还需要获取“FooId”,然后将“ItemId”和“FooId”添加到 ConcurrentDictionary。
我有这个代码。
DataTable table1;
DataTable table2;
var table1Select = table1.Select();
ConcurrentDictionary<double, double> compareDictionary = new ConcurrentDictionary<double, double>();
foreach (var item in table1)
{
var fooItem = from foo in table2.AsEnumerable()
where foo.Field<string>("FooName").Contains(item.Field<string>("ItemName"))
select foo.Field<double>("FooId");
if(fooItem != null && fooItem.FirstOrDefault() != 0)
{
compareDictionary.TryAdd(item.Field<double>("ItemId"), fooItem.FirstOrDefault());
}
}
它工作缓慢(执行任务大约需要 10 分钟)。
我想让它更快。我该如何优化它?
解决方案
我看到你可以攻击三点:
- 放弃对字段访问器的强类型化以支持直接强制转换:它强制取消装箱,您可以完全避免使用
doubles
值类型。upd正如评论中指出的那样,无论哪种方式,您都不会避免拆箱,但可能会节省一些方法调用开销(这又是有争议的)。这一点大概可以忽略 - 缓存引用字符串,因此每个外循环只能访问一次
- (我认为这是最大的收获)因为你似乎总是取第一个结果 -
FirstOrDefault()
在 LINQ 中直接选择 - 不要让它在找到匹配项时枚举整个事情
ConcurrentDictionary<double, double> compareDictionary = new ConcurrentDictionary<double, double>();
foreach (var item in table1)
{
var sample = (string)item["ItemName"]; // cache the value before looping through inner collection
var fooItem = table2.AsEnumerable()
.FirstOrDefault(foo => ((string)foo["FooName"]).Contains(sample)); // you seem to always take First item, so you could instruct LINQ to stop after a match is found
if (fooItem != null && (double)fooItem["FooId"] != 0)
{
compareDictionary.TryAdd((double)item["ItemId"], (double)fooItem["FooId"]);
}
}
看来,将.FirstOrDefault()
条件应用于 LINQ 查询语法无论如何都会将其简化为方法链语法,所以我会一直选择方法链接,并留给你来弄清楚美学
推荐阅读
- xml - 使用身份模板的 XSLT 2.0
- serialization - 反序列化后如何处理SerializationException
- mysql - 2表列出错误在哪里(帮助)
- unity3d - Unity2D:旋转物体保持看前面
- youtube-iframe-api - Hiding YouTube embed title and 'More videos' (Updated)
- javascript - 不要在 IE 中显示带有 Bootstrap 的网站
- java - 在对象上找不到参数 [目录'libs'] 的方法 implementation()
- angular - 在动态 api 调用角度 5 期间无法读取未定义的属性“地图”
- r - 具有在 nrows [R] 之后也休眠的函数的 for 循环
- javascript - three.js 中是否有向函数移动