Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/facebook/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 即使哈希代码相同,LINQ Distinct计数也会重复?_C#_Linq_Hash_Equality - Fatal编程技术网

C# 即使哈希代码相同,LINQ Distinct计数也会重复?

C# 即使哈希代码相同,LINQ Distinct计数也会重复?,c#,linq,hash,equality,C#,Linq,Hash,Equality,我正在按正则表达式模式对日志记录进行分组。在对它们进行分组之后,我想得到每个组的不同记录计数。在本例中,Distinct定义为相同的访问密钥和相同的年、月、日、小时和分钟 这只是一种更准确地统计不同消费者在整个堆栈中记录的内容的方法 好的,我把它们分组如下: var knownMessages = logRecords .Where(record => !string.IsNullOrEmpty(record.InclusionPattern)) .GroupBy(reco

我正在按正则表达式模式对日志记录进行分组。在对它们进行分组之后,我想得到每个组的不同记录计数。在本例中,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);
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;
}
类型的GetHashCode实现如下:

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);
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进行比较,因为我在那里有一个断点来查看哈希代码是什么


我遗漏了什么?

您似乎没有覆盖Equals方法,以使用与哈希代码生成算法相同的相等定义。因为这是用来解决哈希冲突的,所以两者始终保持同步是很重要的。

似乎您还没有覆盖Equals方法以使用与哈希代码生成算法相同的相等定义。因为这是用来解决散列冲突的,所以这两者始终保持同步是很重要的。

您不需要使用Equals覆盖。与其他基于哈希的集合(如Dictionary和HashSet)一样,Distinct使用的内部结构使用GetHashCode来选择要存储的哈希,但使用Equals来确定实际的相等性

问题可能是Equals中的错误或GetHashCode中的错误,但在后一种情况下,它与Equals不正确匹配GetHashCode必须为Equals返回true的两个对象返回相同的哈希值,但当然也可以为两个不同的对象返回相同的哈希值,这使得它成为方法对中的错误。因此,无论哪种方式,问题都直接或间接地存在于对Equals的重写中。

您没有对Equals进行重写。与其他基于哈希的集合(如Dictionary和HashSet)一样,Distinct使用的内部结构使用GetHashCode来选择要存储的哈希,但使用Equals来确定实际的相等性


问题可能是Equals中的错误或GetHashCode中的错误,但在后一种情况下,它与Equals不正确匹配GetHashCode必须为Equals返回true的两个对象返回相同的哈希值,但当然也可以为两个不同的对象返回相同的哈希值,这使得它成为方法对中的错误。因此,无论哪种方式,问题都直接或间接地存在于你对等式的覆盖上。

首先让我重复一下我在评论中所说的

逻辑是:如果a.GetHashcode!=b、 GetHashCode然后是a!=b、 如果a.GetHashCode==b.GetHashCode&&a.Equalsb,那么a==b,GetHashCode为您所做的全部工作就是让您跳过相等检查,如果您有两个不同的值。这就是为什么您需要实现这两个,如果您只实现Equals,那么a.GetHashCode==b.GetHashCode步骤将失败,并且它从不尝试您实现的Equals

GetHashCode应该是快速的,当它位于依赖于它的值的集合中时,它的值不应该改变。因此,如果要将VisitKey或Time存储在字典或哈希集或类似文件中,请不要修改它们

因此,您需要做的就是:

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);
}

首先让我重复一下我在评论中所说的话

逻辑是:如果a.GetHashcode!=b、 GetHashCode然后是a!=b、 如果a.GetHashCode==b.GetHashCode&&a.Equalsb,那么a==b,GetHashCode为您所做的全部工作就是让您跳过相等检查,如果您有两个不同的值。这就是为什么您需要实现这两个,如果您只实现Equals,那么a.GetHashCode==b.GetHashCode步骤将失败,并且它从不尝试您实现的Equals

GetHashCode应该是快速的,当它位于依赖于它的值的集合中时,它的值不应该改变。因此,如果要将VisitKey或Time存储在字典或哈希集或类似文件中,请不要修改它们

因此,您需要做的就是:

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定义的关键。@Servy,我认为如果散列码匹配,它们将被视为相等。您应该实现IEquitable@MichaelPerrenoud不,重要的是始终覆盖两者或两者都不覆盖,而不是只覆盖其中一个,无论何时重写它们都应该使用相同的相等的一般定义,否则就会发生不好的事情。@MichaelPerrenoud逻辑是:If a.GetHashcode!=b、 GetHashCode然后是a!=b、 如果a.GetHashCode==b.GetHashCode&&a.Equalsb,那么a==b,GetHashCode为您所做的全部工作就是让您跳过相等检查,如果您有两个不同的值。这就是为什么您需要实现这两个,如果您只实现了Equals,那么a.GetHashCode==b.GetHashCode步骤将失败,并且它从不尝试您实现的Equals。Firs
t off,在一个不会引起冲突的庄园中,将散列值组合在一起不是一个很好的方法。第二,您还没有展示Equals的定义,这当然是Equals定义的关键。@Servy,我认为如果散列码匹配,它们将被视为相等。您应该实现IEquitable@MichaelPerrenoud不,重要的是始终覆盖两者或两者都不覆盖,而不是只覆盖其中一个,无论何时重写它们都应该使用相同的相等的一般定义,否则就会发生不好的事情。@MichaelPerrenoud逻辑是:If a.GetHashcode!=b、 GetHashCode然后是a!=b、 如果a.GetHashCode==b.GetHashCode&&a.Equalsb,那么a==b,GetHashCode为您所做的全部工作就是让您跳过相等检查,如果您有两个不同的值。这就是为什么您需要实现这两个,如果您只实现了Equals,那么a.GetHashCode==b.GetHashCode步骤将失败,并且它从不尝试您实现的Equals。太棒了!因此,只要类型实际上相同,我就应该从Equals调用GetHashCode;是吗?@MichaelPerrenoud不,因为散列码会发生冲突。相等的散列代码并不意味着相等的对象,除非类型的可能值小于2^32,在这种情况下,有效的散列表示没有散列冲突,您就没事了。好吧,我编写了GetHashCode以使相似对象发生冲突。此外,根据@Scott的评论,强制等于甚至被调用是必要的。那么为什么我不直接从Equals方法调用GetHashCode呢?当然,假设它们是完全相同的类型。@MichaelPerrenoud,因为不同的对象可能有相同的哈希代码。所有相等的对象必须具有相同的has代码,而不是所有不相等的对象都具有不相等的哈希代码。只有2^32个可能的int,但是大多数类型的可能值更多,包括您的。您不能从Equals调用GetHashCode,除非极少数情况下所有可能的值都有不同的哈希代码,即使这样,实现也可能很差。你的Equals做了一个比较,看看他们是否在你所说的任何方面都是相等的,这对于所讨论的类来说意味着相等,通常是一组跨不同字段的相等比较。GetHashCode根据相同的条件生成一个数字。因此,如果x==y意味着x.GetHashCode==y.GetHashCode,但是x.GetHashCode==y.GetHashCode并不保证x==y.Great!因此,只要类型实际上相同,我就应该从Equals调用GetHashCode;是吗?@MichaelPerrenoud不,因为散列码会发生冲突。相等的散列代码并不意味着相等的对象,除非类型的可能值小于2^32,在这种情况下,有效的散列表示没有散列冲突,您就没事了。好吧,我编写了GetHashCode以使相似对象发生冲突。此外,根据@Scott的评论,强制等于甚至被调用是必要的。那么为什么我不直接从Equals方法调用GetHashCode呢?当然,假设它们是完全相同的类型。@MichaelPerrenoud,因为不同的对象可能有相同的哈希代码。所有相等的对象必须具有相同的has代码,而不是所有不相等的对象都具有不相等的哈希代码。只有2^32个可能的int,但是大多数类型的可能值更多,包括您的。您不能从Equals调用GetHashCode,除非极少数情况下所有可能的值都有不同的哈希代码,即使这样,实现也可能很差。你的Equals做了一个比较,看看他们是否在你所说的任何方面都是相等的,这对于所讨论的类来说意味着相等,通常是一组跨不同字段的相等比较。GetHashCode根据相同的条件生成一个数字。因此,如果x==y意味着x.GetHashCode==y.GetHashCode,但是x.GetHashCode==y.GetHashCode并不保证x==y.+1。我将order Object.ReferenceEquals更改为first,然后使用as强制转换。我还将使用ifObject.ReferenceEqualsmessage,null而不是ifmessage==null,因为==运算符可以重载,如果它再次调用Equals,将导致StackOverFlowException。这是非常常见的错误:+1。我将order Object.ReferenceEquals更改为first,然后使用as强制转换。我还将使用ifObject.ReferenceEqualsmessage,null而不是ifmessage==null,因为==运算符可以重载,如果它再次调用Equals,将导致StackOverFlowException。这是一个非常常见的错误: