C# 作为字典中的键访问双数组的最快方法

C# 作为字典中的键访问双数组的最快方法,c#,c#-4.0,C#,C# 4.0,我有一个double[]数组,我想将它用作键(不是字面意义上的,而是在需要匹配double数组中的所有double时匹配键的方式) 使用double[]数组作为字典键的最快方法是什么 它在使用吗 字典(将double[]转换为字符串) 或 假设转换所有的密钥数组都具有相同的长度,或者考虑使用元组< /代码>,或者使用数组上的结构相等比较器。 对于元组: var yourDidt = new Dictionary<Tuple<double, double, double>, st

我有一个
double[]
数组,我想将它用作键(不是字面意义上的,而是在需要匹配double数组中的所有double时匹配键的方式)

使用
double[]
数组作为字典键的最快方法是什么

它在使用吗
字典
(将double[]转换为字符串) 或 假设转换所有的密钥数组都具有相同的长度,或者考虑使用<代码>元组< /代码>,或者使用数组上的结构相等比较器。 对于元组:

var yourDidt = new Dictionary<Tuple<double, double, double>, string>();
yourDict.Add(Tuple.Create(3.14, 2.718, double.NaN), "da value");

string read = yourDict[Tuple.Create(3.14, 2.718, double.NaN)];

还考虑Sergey Berezovskiy提出的创建自定义类或(不可变的)的建议。Stutt来保存你的代码集>双< /代码> .S.这样你就可以用一种自然的方式命名你的类型和它的成员,使你更清楚你所做的事情。如果需要的话,你的类/结构可以很容易地被扩展。

假设所有的密钥数组都有相同的长度,或者考虑使用<代码>元组< /代码>,或者使用一个结构等式。数组上的比较器

对于元组:

var yourDidt = new Dictionary<Tuple<double, double, double>, string>();
yourDict.Add(Tuple.Create(3.14, 2.718, double.NaN), "da value");

string read = yourDict[Tuple.Create(3.14, 2.718, double.NaN)];

还考虑Sergey Berezovskiy提出的创建自定义类或(不可变的)的建议。结构来保存你的

double
s集合。这样你可以用一种自然的方式来命名你的类型和它的成员,使你的操作更加清晰。如果需要的话,你的类/结构以后可以很容易地扩展。

因此所有数组都有相同的长度,数组中的每一项都有特定的含义,然后创建一个类来保存所有的项具有描述性名称的属性。例如,您可以使用带有属性
X
Y
的类
,而不是带有两个项的双数组。然后重写该类的
等于
GetHashCode
,并将其用作键(请参阅):


因此,所有数组都具有相同的长度,数组中的每个项都有特定的含义,然后创建一个类,该类将所有项作为具有描述性名称的属性保存。例如,您可以使用具有属性的class
Point
Y
。然后覆盖
Equals
GetHashCode>并将其用作键(请参阅):


[P>]不认为这是一个单独的答案;这是@ JpppStnnelels'的回答[/P>的延伸]。 我只想指出,您将Jeppe的方法概括如下:

public class StructuralEqualityComparer<T>: IEqualityComparer<T>
{
    public bool Equals(T x, T y)
    {
        return StructuralComparisons.StructuralEqualityComparer.Equals(x, y);
    }

    public int GetHashCode(T obj)
    {
        return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj);
    }

    public static StructuralEqualityComparer<T> Default
    {
        get
        {
            StructuralEqualityComparer<T> comparer = _defaultComparer;

            if (comparer == null)
            {
                comparer = new StructuralEqualityComparer<T>();
                _defaultComparer = comparer;
            }

            return comparer;
        }
    }

    private static StructuralEqualityComparer<T> _defaultComparer;
}

[P>]不认为这是一个单独的答案;这是@ JpppStnnelels'的回答[/P>的延伸]。 我只想指出,您将Jeppe的方法概括如下:

public class StructuralEqualityComparer<T>: IEqualityComparer<T>
{
    public bool Equals(T x, T y)
    {
        return StructuralComparisons.StructuralEqualityComparer.Equals(x, y);
    }

    public int GetHashCode(T obj)
    {
        return StructuralComparisons.StructuralEqualityComparer.GetHashCode(obj);
    }

    public static StructuralEqualityComparer<T> Default
    {
        get
        {
            StructuralEqualityComparer<T> comparer = _defaultComparer;

            if (comparer == null)
            {
                comparer = new StructuralEqualityComparer<T>();
                _defaultComparer = comparer;
            }

            return comparer;
        }
    }

    private static StructuralEqualityComparer<T> _defaultComparer;
}

好的,这是我到目前为止发现的:

我在字典中输入一个条目(长度为4 arrray),并在我的机器上访问它999999次:

字典(
新的DoubleArrayStructuralQualityComparer());
需要
1.75秒

字典
需要
0.85秒

下面的代码需要
0.1755285秒
,这是现在最快的速度!(与Sergey的评论一致)

最快的-Matthew Watson的
DoubleArrayComparer
代码需要
0.15秒

    public class DoubleArray
    {
        private double[] d = null;
        public DoubleArray(double[] d)
        {
            this.d = d;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is DoubleArray)) return false;

            DoubleArray dobj = (DoubleArray)obj;
                if (dobj.d.Length != d.Length) return false;

                for (int i = 0; i < d.Length; i++)
                    {
                        if (dobj.d[i] != d[i]) return false;
                    }
                return true;

        }
        public override int GetHashCode()
        {
            unchecked // Overflow is fine, just wrap
            {
                int hash = 17;
                for (int i = 0; i < d.Length;i++ )
                {
                    hash = hash*23 + d[i].GetHashCode();
                }

                return hash;
            }
        }
    }
公共类双数组
{
private double[]d=null;
公共双数组(双[]d)
{
这个。d=d;
}
公共覆盖布尔等于(对象对象对象)
{
如果(!(obj为DoubleArray))返回false;
双数组dobj=(双数组)obj;
如果(dobj.d.Length!=d.Length)返回false;
对于(int i=0;i
好的,这是我目前发现的:

我在字典中输入一个条目(长度为4 arrray),并在我的机器上访问它999999次:

字典(
新的DoubleArrayStructuralQualityComparer());
需要
1.75秒

字典
需要
0.85秒

下面的代码需要
0.1755285秒
,这是现在最快的速度!(与Sergey的评论一致)

最快的-Matthew Watson的
DoubleArrayComparer
代码需要
0.15秒

    public class DoubleArray
    {
        private double[] d = null;
        public DoubleArray(double[] d)
        {
            this.d = d;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is DoubleArray)) return false;

            DoubleArray dobj = (DoubleArray)obj;
                if (dobj.d.Length != d.Length) return false;

                for (int i = 0; i < d.Length; i++)
                    {
                        if (dobj.d[i] != d[i]) return false;
                    }
                return true;

        }
        public override int GetHashCode()
        {
            unchecked // Overflow is fine, just wrap
            {
                int hash = 17;
                for (int i = 0; i < d.Length;i++ )
                {
                    hash = hash*23 + d[i].GetHashCode();
                }

                return hash;
            }
        }
    }
公共类双数组
{
private double[]d=null;
公共双数组(双[]d)
{
这个。d=d;
}
公共覆盖布尔等于(对象对象对象)
{
如果(!(obj为DoubleArray))返回false;
双数组dobj=(双数组)obj;
如果(dobj.d.Length!=d.Length)返回false;
对于(int i=0;i
Yo知道两个具有相同值的数组将给出不同的键(因为它们不相等)?为什么要将数组用作键,而不将其自身加倍?@SergeyBerezovskiy我已经改变了问题Dictionary有什么问题?@NWard基本上我需要的是数组中的所有加倍都要匹配。你知道两个数组具有相同的
class DoubleArrayComparer: IEqualityComparer<double[]>
{
    public bool Equals(double[] x, double[] y)
    {
        if (x == y)
            return true;

        if (x == null || y == null)
            return false;

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

        for (int i = 0; i < x.Length; ++i)
            if (x[i] != y[i])
                return false;

        return true;
    }

    public int GetHashCode(double[] data)
    {
        if (data == null)
            return 0;

        int result = 17;

        foreach (var value in data)
            result += result*23 + value.GetHashCode();

        return result;
    }
}

...

var yourDict = new Dictionary<double[], string>(new DoubleArrayComparer());
    public class DoubleArray
    {
        private double[] d = null;
        public DoubleArray(double[] d)
        {
            this.d = d;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is DoubleArray)) return false;

            DoubleArray dobj = (DoubleArray)obj;
                if (dobj.d.Length != d.Length) return false;

                for (int i = 0; i < d.Length; i++)
                    {
                        if (dobj.d[i] != d[i]) return false;
                    }
                return true;

        }
        public override int GetHashCode()
        {
            unchecked // Overflow is fine, just wrap
            {
                int hash = 17;
                for (int i = 0; i < d.Length;i++ )
                {
                    hash = hash*23 + d[i].GetHashCode();
                }

                return hash;
            }
        }
    }