在列表中不同<List<double>>

Distinct on List<List<double>>

genesUsingCrossover 是 List<List<double>>.

我正在使用以下代码行来计算 List<List<double>> 中的不同 List<double>

int count = genesUsingCrossover.Distinct().Count();

我不确定它是否正确。 genesUsingCrossover 中的元素数是 1250,而且 genesUsingCrossover.Distinct().Count() 返回 1250,所以我假设它们都是不同的列表。但是,查看手表 window 我注意到第三和第四个列表是相同的。

因此,我认为这行代码不正确。有没有办法改善它?并计算不同元素的数量?

事实上,您没有定义两个列表被视为相等的条件。 这意味着 .NET 默认检查两个列表在内存中是否具有相同的引用,因为 Listreference type

不言而喻,每个榜单都有他的记忆。所以你的列表有 1205 个元素,returns 1205 个元素不同。

根据您的描述,我认为您的标准是:包含相同元素的 2 个列表应该相等。

Distinct可以收到一个IEqualityComparer,所以思路是:为List<double>

实现IEqualityComparer
class NumberDoubles: IEqualityComparer<List<double>>
{
    public bool Equals(List<double> x, List<double> y)
    {
        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        if (x.Count!= y.Count)
            return false;

        //Check whether the arrays' values are equal.
        for(int i = 0; i < x.Count; i++){
            if(x[i] != y[i])
                return false;
        }

        // If got this far, arrays are equal
        return true;
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.

    public int GetHashCode(List<double> doubleArray)
    {
        //Check whether the object is null
        if (Object.ReferenceEquals(doubleArray, null)) return 0;

        //Calculate the hash code for the array
        int hashCode = 0;
        bool isFirst = true;
        foreach(int i in doubleArray){
            if(isFirst) {
                hashCode = i;
                isFirst = false;
            }
            else
            {
                hashCode = hashCode ^ i;
            }
        }
        return hashCode;
    }
}

和您的代码:

genesUsingCrossover.Distinct(new NumberDoubles());

List<T> doesn't override Object.Equals, so two List<double> objects will only be considered equal if they're reference-equal. (Here is the implementation of Distinct<T>() if you want to see how it works.) It sounds like you want to consider two lists to be equal if the elements that compose them are equal. For this you can use an overload of Distinct<T>() 采用 IEqualityComparer<T>,它将用于确定两个列表是否相等。因此,在您的情况下,您可以提供 IEqualityComparer<List<double>> 的实现来表达您对列表相等性的想法。

该实现的外观取决于您希望何时将两个列表视为相等。例如,它们必须具有相同顺序的相同元素集,还是顺序不相关? Stack Overflow 上还有其他问题解释了如何实现两者。在任何一种情况下,请记住 Distinct() 将多次调用您的实现,因此您的算法执行良好非常重要。为此,可能值得询问 List<List<double>> 是否真的是您想要的数据结构,或者其他选择是否更适合。

就像@Joe 说的那样,您应该真正思考“我真的需要 List<List<double>> 吗?对我来说这听起来像是一个不适合这份工作的结构。区别可以通过 HashSet 开箱即用(好吧,不完全是你的情况,但总的来说,每次有人看到 HashSet 希望它敲响警钟,表明需要唯一性,而 List<List<double>> 不一定表明这一点。

话虽如此,我建议您使用 HashSet<List<double>>

的以下解决方案
using System;
using System.Collections.Generic;
using System.Linq;

public static class Program {
    public static void Main() {
        var hashSet = new HashSet<List<double>>(new ListComparer());

        hashSet.Add(new List<double> { 1.2d, 1.5d });
        hashSet.Add(new List<double> { 1.2d, 1.5d });

        Console.Write(hashSet.Count);
    }

    public class ListComparer : IEqualityComparer<List<double>> 

    {
        public bool Equals(List<double> x, List<double> y)
        {
            // your logic for equality
            return true;
        }

        public int GetHashCode(List<double> obj)
        {
           int hash = 0;
           unchecked {
               foreach(var d in obj) {
                   hash += d.GetHashCode();
               }
           }
           return hash;
        }  
    }
}

请记住,Equals 方法将被调用很多次,因此考虑一些性能方面的考虑可能会有所帮助。