简体   繁体   English

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

[英]fastest way for accessing double array as key in dictionary

I have a double[] array, i want to use it as key (not literally, but in the way that the key is matched when all the doubles in the double array need to be matched) 我有一个double[]数组,我想将它用作键(不是字面意义,而是当double数组中的所有double都需要匹配时,以匹配键的方式)

What is the fastest way to use the double[] array as key to dictionary? double[]数组用作字典键的最快方法是什么?

Is it using Dictionary<string, string> (convert double[] to a string) or anything else like converting it 它是使用Dictionary<string, string> (将double []转换为字符串)还是其他类似的转换方式?

Given that all key arrays will have the same length , either consider using a Tuple<,,, ... ,> , or use a structural equality comparer on the arrays. 假定所有键数组都具有相同的长度 ,则可以考虑在数组上使用Tuple<,,, ... ,>或使用结构相等比较器。

With tuple: 与元组:

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

With (strongly typed version of) StructuralEqualityComparer : 使用( StructuralEqualityComparer化版本的)(强类型版本):

class DoubleArrayStructuralEqualityComparer : EqualityComparer<double[]>
{
    public override bool Equals(double[] x, double[] y)
    {
        return System.Collections.StructuralComparisons.StructuralEqualityComparer
            .Equals(x, y);
    }

    public override int GetHashCode(double[] obj)
    {
        return System.Collections.StructuralComparisons.StructuralEqualityComparer
            .GetHashCode(obj);
    }
}

...

var yourDict = new Dictionary<double[], string>(
    new DoubleArrayStructuralEqualityComparer());

yourDict.Add(new[] { 3.14, 2.718, double.NaN, }, "da value");

string read = yourDict[new[] { 3.14, 2.718, double.NaN, }];

Also consider the suggestion by Sergey Berezovskiy to create a custom class or (immutable!) struct to hold your set of double s. 还可以考虑Sergey Berezovskiy的建议,以创建一个自定义类或(不可变!)结构来保存您的double集合。 In that way you can name your type and its members in a natural way that makes it more clear what you do. 这样,您就可以以一种自然的方式来命名您的类型及其成员,从而使您的工作更加清晰。 And your class/struct can easily be extended later on, if needed. 如果需要,您的类/结构可以在以后轻松扩展。

Thus all arrays have same length and each item in array have specific meaning, then create class which holds all items as properties with descriptive names. 因此,所有数组都具有相同的长度,并且数组中的每个项目都有特定的含义,然后创建一个类,该类将所有项目作为具有描述性名称的属性来保存。 Eg instead of double array with two items you can have class Point with properties X and Y . 例如,可以使用具有属性XY Point类来代替具有两个项目的double数组。 Then override Equals and GetHashCode of this class and use it as key (see What is the best algorithm for an overriding GetHashCode ): 然后重写此类的EqualsGetHashCode并将其用作键(请参阅什么是重写GetHashCode的最佳算法 ):

Dictionary<Point, string>

Benefits - instead of having array, you have data structure which makes its purpose clear. 好处-您不用拥有数组,而是拥有清楚说明其目的的数据结构。 Instead of referencing items by indexes, you have nice named property names, which also make their purpose clear. 不用按索引引用项目,而是使用漂亮的命名属性名称,这也可以使它们的用途明确。 And also speed - calculating hash code is fast. 而且速度-计算哈希码的速度也很快。 Compare: 相比:

double[] a = new [] { 12.5, 42 };
// getting first coordinate a[0];
Point a = new Point { X = 12.5, Y = 42 };
// getting first coordinate a.X

[Do not consider this a separate answer; [不要认为这是一个单独的答案; this is an extension of @JeppeStigNielsen's answer] 这是@JeppeStigNielsen的答案的扩展]

I'd just like to point out that you make Jeppe's approach generic as follows: 我只想指出,您使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;
}

(From an original answer here: https://stackoverflow.com/a/5601068/106159 ) (从原始答案在这里: https : //stackoverflow.com/a/5601068/106159

Then you would declare the dictionary like this: 然后,您将这样声明字典:

var yourDict  = new Dictionary<double[], string>(new StructuralEqualityComparer<double[]>());

Note: It might be better to initialise _defaultComparer using Lazy<T> . 注意:最好使用Lazy<T>初始化_defaultComparer


[EDIT] [编辑]

It's possible that this might be faster; 这可能会更快。 worth a try: 值得一试:

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

Ok this is what I found so far: 好的,这是我到目前为止发现的:

I input an entry (length 4 arrray) to the dictionary, and access it for 999999 times on my machine: 我在字典中输入了一个条目(长度为4 arrray),并在我的机器上访问了999999次:

Dictionary<double[], string>( new DoubleArrayStructuralEqualityComparer()); takes 1.75 seconds 需要1.75 seconds

Dictionary<Tuple<double...>,string> takes 0.85 seconds Dictionary<Tuple<double...>,string>花费0.85 seconds

The code below takes 0.1755285 seconds , which is the fastest now! 下面的代码需要0.1755285 seconds ,这是现在最快的! (in line with the comment with Sergey.) (与谢尔盖的评论一致。)

The fastest - The code of DoubleArrayComparer by Matthew Watson takes 0.15 seconds ! 最快DoubleArrayComparer Watson编写的DoubleArrayComparer代码需要0.15 seconds

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM