[英]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
. 例如,可以使用具有属性X
和Y
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 ): 然后重写此类的Equals
和GetHashCode
并将其用作键(请参阅什么是重写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.