我有大约170,000个单词的集合,我对它们执行了许多操作。最常见的是:StartsWith,EndsWith和Contains。我也做了很多长度检查。
我最初将此信息存储在List<string>
中,但随后切换为HashSet<string>
,因为我认为此类数据会更快。
根据我的描述,HashSet是这个数据的最佳集合类型吗?
答案 0 :(得分:5)
trie是一个非常好的数据结构,用于存储字符串和执行所需的文本搜索操作。它是常用于索引字符串值的数据结构,用于搜索引擎,如Lucene
通常,当提到时,trie被描述为前缀树,它允许非常有效的“开始于”搜索。数据结构的suffix tree变体在搜索结束时非常有效。
可以想象,通过在填充trie时以及搜索trie时简单地反转字符串,可以对前缀树和后缀树使用相同的trie实现。
答案 1 :(得分:2)
我假设您正在尝试查找StartsWith
,EndWith
或Contains
某些搜索字词的匹配项。如果是这种情况那么你是正确的List
并不理想。我不相信Hashset
更好。
查看trie。我不会构建一个,但如果给出一些关于问题空间的背景。该算法包括按照初始子字符串对单词进行分组 - 基于第一个字母的单词组,然后按第二个字母对子组进行分组,依此类推。
我过去做过这个时,我已经使用了Lookup类,并且还实现了Dictionary<string, List<string>>
。
我使用的算法大致是
var dictionary = new Dictionary<int, Lookup<string, string>>();
for (int i = 1; i < maxWordLength; i++)
{
// get all words with i or more letters
dictionary.Add(i, words.ToLookup(w => w.Substring(i)));
}
然后找到像
这样的单词var word = "TestWord";
var matches = dictionary[word.Length][word];
如果您还需要EndsWith
和Contains
,那么您可能还需要一些索引结构。
答案 2 :(得分:1)
您提到的操作都是在集合的个别元素上完成的,因此他们完全不了解您的元素实际来自哪种类型的集合。
集合类型需要考虑的重要事项是您使用整个集合的方式:您是否经常插入项目,或经常删除它们?您想要按顺序获取每个元素,还是想要更频繁地访问集合的特定部分?该集合可以有重复的元素吗?你需要检查会员资格吗?您处理它们的顺序是否重要?
这些是您需要回答的问题类型,以便就不同的收集类型做出明智的决定。
答案 3 :(得分:1)
这听起来像是Lucene的工作。但是,如果您决定实现自己的算法(无论可能是什么),那么最好的办法是在Parallel.ForEach和PLINQ中利用C#强大的并行循环结构。
Data Parallelism (Task Parallel Library)
即
var source = Enumerable.Range(100, 20000);
// Result sequence might be out of order.
var parallelQuery = from num in source.AsParallel()
where num % 10 == 0
select num;
答案 4 :(得分:0)
如果列表是静态的,那么最好的可能是一个字符串数组,因为它具有最低的开销。
然后使用多个线程。
答案 5 :(得分:0)
跑了一个测试但没有得到我预期的答案。列表和HashSet和AsParallel大致相同(但只有2个核心机器)。 .NET 4.0和600,000个单词的列表。
我回应第一条评论。当有疑问时测试。 l是List,h是HashSet。
Debug.WriteLine("lWords.Count hWords.Count " + lWords.Count.ToString() + " " + hWords.Count.ToString());
Stopwatch SW = new Stopwatch();
SW.Restart();
Debug.WriteLine("H count " + hWords.Where(value => value.StartsWith("s")).Count().ToString());
SW.Stop();
Debug.WriteLine("H time " + SW.ElapsedMilliseconds.ToString());
SW.Restart();
SW.Stop();
Debug.WriteLine("Start Stop " + SW.ElapsedMilliseconds.ToString());
SW.Restart();
Debug.WriteLine("L count " + lWords.Where(value => value.StartsWith("s")).Count().ToString());
SW.Stop();
Debug.WriteLine("L time " + SW.ElapsedMilliseconds.ToString());
SW.Restart();
Debug.WriteLine("H count " + hWords.Where(value => value.StartsWith("s")).Count().ToString());
SW.Stop();
Debug.WriteLine("H time " + SW.ElapsedMilliseconds.ToString());
SW.Restart();
Debug.WriteLine("L count " + lWords.AsParallel().Where(value => value.StartsWith("s")).Count().ToString());
SW.Stop();
Debug.WriteLine("L time parallel " + SW.ElapsedMilliseconds.ToString());
SW.Restart();
Debug.WriteLine("H count " + hWords.AsParallel().Where(value => value.StartsWith("s")).Count().ToString());
SW.Stop();
Debug.WriteLine("H time parallel " + SW.ElapsedMilliseconds.ToString());
Debug.WriteLine("");
output:
lWords.Count hWords.Count 667309 667309
H count 45851
H time 283
Start Stop 0
L count 45851
L time 285
H count 45851
H time 364
L count 45851
L time parallel 307
H count 45851
H time parallel 344