我正在处理这样一个事实:我需要使用一组元素初始化一个HashSet,但没有任何类型的比较类。
在init之后,添加到HashSet的任何元素都需要与比较器一起传递。
我怎样才能完成它?
现在我有了这个:
HashSet<Keyword> set = new HashSet<Keyword>(new KeyWordComparer());
问题在于,init需要很长时间,并且没有必要应用比较。
KeywordComparer类:
class KeyWordComparer : EqualityComparer<Keyword>
{
public override bool Equals(Keyword k1, Keyword k2)
{
int equals = 0;
int i = 0;
int j = 0;
// based on sorted ids
while (i < k1._lista_modelos.Count && j < k2._lista_modelos.Count)
{
if (k1._lista_modelos[i] < k2._lista_modelos[j])
{
i++;
}
else if (k1._lista_modelos[i] > k2._lista_modelos[j])
{
j++;
}
else
{
equals++;
i++;
j++;
}
}
return equals >= 8;
}
public override int GetHashCode(Keyword keyword)
{
return 0;//notice that using the same hash for all keywords gives you an O(n^2) time complexity though.
}
}
注意:这是c# comparing list of IDs的后续问题。
答案 0 :(得分:1)
每个关键字都有20个ID,因此当我想向HashSet添加新的关键字时,KeywordComparer会检查新的关键字与HashSet的任何关键字重复的ID不超过8个。如果不包含新关键字,则不包括在内。
收集这些关键字不是此处哈希集的工作。哈希集通常不适用于依赖于集合的其他元素的项目。您应该只将它用于可以为每个项计算有用哈希的事项。由于它取决于现有项目集是否将新项目添加到您的集合中,这完全是错误的工具。
根据您对实际操作的简短描述,尝试解决此问题。在这里,我们只是在列表中收集关键字。为了验证它们是否可以添加,我们使用附加哈希集来收集关键字的ID 。这样,我们可以快速检查新项目,其中8个或更多的ID是否已包含在关键字列表中。
var keywords = new List<Keyword>();
var selectedIds = new HashSet<int>(); // I’m assuming that the ids are ints here
foreach (var keyword in GetListOfAllKeywords())
{
// count the number of keyword ids that are already in the selectedIds set
var duplicateIdCount = keyword.Ids.Count(id => selectedIds.Contains(id));
if (duplicateIdCount <= 8)
{
// less or equal to 8 ids are already selected, so add this keyword
keywords.Add(keyword);
// and collect all the keyword’s ids
selectedIds.AddRange(keyword.Ids);
}
}
答案 1 :(得分:0)
如果我远离这个事实,如果使用HashSet是适合手头工作的类型,或者如果你的Comparer甚至是有意义的,那么实现一个合适的GetHashCode
确实会产生巨大的差异。
以下是基于answer的Marc Gravell的示例实现:
class KeyWordComparer : EqualityComparer<Keyword>
{
// omitted your Equals implentaton for brevity
public override int GetHashCode(Keyword keyword)
{
//return 0; // this was the original
// Marc Gravell https://stackoverflow.com/a/371348/578411
int hash = 13;
// not sure what is up with the only 8 ID's but I take that as a given
for(var i=0; i < Math.Min(keyword._lista_modelos.Count, 8) ; i++)
{
hash = (hash * 7) + keyword._lista_modelos[i].GetHashCode();
}
return hash;
}
}
当我使用此测试装置在LinqPad中运行时
Random randNum = new Random();
var kc = new KeyWordComparer();
HashSet<Keyword> set = new HashSet<Keyword>(kc);
var sw = new Stopwatch();
sw.Start();
for(int i =0 ; i< 10000; i++)
{
set.Add(new Keyword(Enumerable
.Repeat(0, randNum.Next(1,10))
.Select(ir => randNum.Next(1, 256)).ToList()));
}
sw.Stop();
sw.ElapsedMilliseconds.Dump("ms");
这是我衡量的:
如果我切换回return 0;
实施GetHashCode
I measure
如果我增加了testloop以插入100,000个项目,那么更好的GetHashCode仍会在224毫秒内完成。我没等你的实施完成。
因此,如果有任何实现正确的GetHashCode
方法。