LINQ Distinct计数重复,即使哈希代码相同
本文关键字:哈希 代码 Distinct LINQ | 更新日期: 2023-09-27 17:58:53
我正在按RegEx模式对日志记录进行分组。在对它们进行分组之后,我想获得每组的记录的Distinct
计数。在本例中,Distinct
被定义为相同的访问密钥和相同的年、月、日、小时和分钟。
这只是一种更准确地统计不同消费者记录的内容的方法。
好吧,所以我把它们分组如下:
var knownMessages = logRecords
.Where(record => !string.IsNullOrEmpty(record.InclusionPattern))
.GroupBy(record => new
{
MessagePattern = record.InclusionPattern
})
.Select(g => new KnownMessage
{
MessagePattern = g.Key.MessagePattern,
----> Count = g.Distinct().Count(),
Records = g.ToList()
})
.OrderByDescending(o => o.Count);
类型的GetHashCode
是这样实现的:
public override int GetHashCode()
{
var visitKeyHash = this.VisitKey == null ?
251 : this.VisitKey.GetHashCode();
var timeHash = this.Time.Year + this.Time.Month + this.Time.Day +
this.Time.Hour + this.Time.Minute;
return ((visitKeyHash * 251) + timeHash) * 251;
}
但是,例如,在列表中,我有三条记录返回相同的哈希代码1439926797
;我仍然得到3
的计数。我知道它正在利用GetHashCode
(正如我所期望的)来进行比较,因为我在那里有一个断点来查看哈希代码是什么
我错过了什么?
首先让我重复一下我在评论中所说的话。
逻辑是:如果a.GetHashcode() != b.GetHashCode()
然后a != b,
如果a.GetHashCode() == b.GetHashCode() && a.Equals(b)
然后a == b
,那么所有GetHashcode()
为您所做的就是让您跳过Equals()
检查,如果您有两个不同的值。这就是为什么你需要同时实现这两个。如果你只实现Equals()
,那么a.GetHashCode() == b.GetHashCode()
步骤就会失败,它永远不会尝试你实现的Equals()。
GetHashCode()
应该很快,并且当它位于依赖于它的值的集合中时,它的值不应该改变。因此,如果要将VisitKey
或Time
存储在Dictionary
或HashSet
或类似文件中,请不要修改它们。
所以你所需要做的就是:
public override int GetHashCode()
{
var visitKeyHash = this.VisitKey == null ?
251 : this.VisitKey.GetHashCode();
var timeHash = this.Time.Year + this.Time.Month + this.Time.Day +
this.Time.Hour + this.Time.Minute;
return ((visitKeyHash * 251) + timeHash);
}
public override bool Equals(object obj)
{
//Two quick tests before we start doing all the math.
if(Object.ReferenceEquals(this, obj))
return true;
KnownMessage message = obj as KnownMessage;
if(Object.ReferenceEquals(message, null)))
return false;
return this.VisitKey.Equals(message.VisitKey) &&
this.time.Year.Equals(message.Time.Year) &&
this.time.Month.Equals(message.Time.Month) &&
this.time.Day.Equals(message.Time.Day) &&
this.time.Hour.Equals(message.Time.Hour) &&
this.time.Minute.Equals(message.Time.Minute);
}
您似乎没有重写Equals
方法,以便使用与哈希代码生成算法相同的相等定义。由于这是用来解决散列冲突的,所以两者始终保持同步是很重要的。
您不提供Equals
覆盖。与其他基于哈希的集合(如Dictionary
和HashSet
)一样,Distinct()
使用的内部结构使用GetHashCode()
来选择要存储的哈希,但使用Equals
来确定实际的相等性。
问题可能是Equals
或GetHashCode
中的错误,但在后一种情况下,它与Equals
不正确匹配(GetHashCode必须为Equals
返回true的两个对象返回相同的散列,但当然也可以为两个不同的对象返回相同散列),这使它成为这对方法中的错误。因此,无论哪种方式,问题都直接或间接存在于您对Equals
的覆盖中。