我有一本非常庞大的字典,里面的内容看起来像:
(标题不包含在字典中)
(code) (names)
------------------------------
910235487 Diabetes, tumors, sugar sick, .....
我在字典中有超过150K这种对的行。
用户输入是关键词(诊断名称),我无法按键搜索词典。
以下是代码:
var relevantIDs = this.dic.Where(ele => ele.Value.Contains(keyword)).Select(n => Convert.ToUInt64(n.Key));
字典是Dictionary<string, string>
,我必须使用字符串作为密钥的数据类型,因为代码有时可能包含字符。 names列包含相关诊断名称的列表。所以我也不能改变这种数据类型。
我认为问题出在一对的每个值上,我做了Contains
操作,这会减慢who进程的速度,但我找不到另一种方法...
这是我为了找到匹配的代码所做的 但是这段代码的性能非常糟糕(完成这一行代码需要大约5分钟)。
有人可以帮忙吗?
更新和最简单的解决方案:
我终于找到了搜索速度如此之慢的季节,并通过这样做解决了这个问题:
var relevantStringIDs = this.dic.Where(ele => ele.Value.Contains(keyword)).Tolist();
var relevantUlongIDs = relevantStringIDs.Select(n => Convert.ToUInt64(n.Key)).Tolist();
缓慢的原因是this.dic.Where(ele => ele.Value.Contains(keyword))
,每次执行查询的第二部分时都会执行(这是IEnumberable<T>
的功能,我忘记了它的用语(也许延迟执行))。因此,我使用ToList()
将延迟查询转换为内存中的具体列表,以便在将字符串转换为ulongs
时可以重用结果,而不是为每次转换再次执行查询。
如果您在此解释中发现错误,请纠正我。
顺便说一下,虽然这可能不是最佳解决方案,但改变后的代码的性能却安静得令人满意。代码的第一个陈述只花费169毫秒,这对我来说足够快。
答案 0 :(得分:4)
你这样做是错误的。当您知道键而不是值时,词典允许有效的查找。
修复性能的一种简单方法是构建一个反向字典,模仿内容的全文索引:
var dic = new Dictionary<string, string>();
dic.Add("910235487", "Diabetes, tumors, sugar sick");
dic.Add("120391052", "Fever, diabetes");
char[] delimiters = new char[] { ' ', ',' };
var wordCodes =
from kvp in dic
from word in kvp.Value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries)
let code = long.Parse(kvp.Key)
select new { Word = word, Code = code };
var fullTextIndex =
wordCodes.ToLookup(wc => wc.Word, wc => wc.Code, StringComparer.OrdinalIgnoreCase);
long[] test1 = fullTextIndex["sugar"].ToArray(); // Gives 910235487
long[] test2 = fullTextIndex["diabetes"].ToArray(); // Gives 910235487, 120391052
全文索引的构建需要很长时间;但是,这是一次性成本,并将通过后续查找的时间节省来摊销。
答案 1 :(得分:2)
你的问题是你通过迭代它的值来失去字典的所有速度优势。字典针对键查找进行了优化。
我会使用不同的数据类型来处理此问题,并针对您的关键字查找进行优化。
这是一个使用LINQ从类似于您的数据创建Lookup的示例。在这种情况下,我直接从字符串数据构建它,这完全避免了字典。
这种类型的查找应该表现得更好。
string [] lines = {
"123 A, B, C, D",
"456 E, F, G",
"321 A, E, H, I",
"654 B, G",
"789 A, J, K, L",
"987 A, M, L, E"
};
var lookup = lines.SelectMany (
l => (l.Split(new char[]{' '},2)[1]).Split(',').Select (v => v.Trim().ToLower()).ToArray(),
(l,o) => new{
keyword = o,
code = Convert.ToInt64(l.Split(' ')[0])
}).ToLookup(k => k.keyword, v => v.code).Dump();
Console.WriteLine(String.Join(",",lookup["a"]));
Console.WriteLine(String.Join(",",lookup["l"]));
Console.WriteLine(String.Join(",",lookup["b"]));
请注意,这假设您正在查找整个关键字(您的初始示例可能会查找部分关键字)