【问题标题】:Best collection to use with type Double as key使用 Double 类型作为键的最佳集合
【发布时间】:2012-02-10 15:41:59
【问题描述】:

我有这个对象:

Public Cactus{
    Public Double key;
    Public String value;
}

我有大约 100 个 Cactus,它们都有一个唯一的键和一个有一些重复的值。 但是,我将不得不检索大约 2000 次键的值。 我的 Key 值在 -10 到 280 之间变化。

我希望这个过程尽可能快。最好的方法是什么?我在考虑使用HashTable,尽管我总是使用Integer 而不是Double,出于某种原因,我担心将Double 用作Key 不是一个好习惯。

根据我的情况,哪个集合最适合使用?

【问题讨论】:

  • 将你的双打转换成字符串并作为键,我想这更可行和有利可图:D
  • 为什么不能使用UInt64 作为密钥(假设密钥必须是 64 位长)?
  • 所讨论的对象基于“真实世界”对象,并且在整个应用程序中几乎都在使用它。我不能完全“破解”自己的 ID,而不必重构过去 10 年所做的一切。希望我没有误解UInt64 的意图!

标签: c# collections


【解决方案1】:

在字典中使用双精度作为键通常是一个非常糟糕的主意。你会遇到各种表示错误的问题,你认为你在字典中存储了 0.1,但实际上你存储的东西非常接近但不完全等于 0.1。

如果您需要完全匹配,我建议使用其他类型(字符串?)。

如果您不想要完全匹配而只想找到最接近的值,请考虑使用类似 SortedList 的方法。

【讨论】:

  • 恐怕这是不可能的,我已经研究了更好的方法来为我的“仙人掌”设置一个唯一标识符,而这几乎就是我所拥有的一切......哦,快乐!
  • 您不需要摆脱现有的双重标识符来执行此操作。他们的键是一个字符串(双截断/四舍五入的某种表示形式),值是您的 Cactus 对象,以便仍然保留真正的(双)键。
【解决方案2】:

是的,使用双精度值作为键似乎很尴尬。 这些双值是否是某些计算的结果,可能有一些非常小的舍入误差? 如果您要计算这些值并使用这些计算值访问集合,则很可能会出现不需要的结果。

例如,您存储一个键值为 1.01 的元素。 您的计算结果为 1.010000000000000123,并且与存储的密钥不匹配。

如果不是这种情况,那么我认为使用双精度值作为字典或哈希表集合的键没有问题。

顺便说一句,使用类型化字典(即Dictionary<double, string>)将比HashTable 更易于使用。

【讨论】:

    【解决方案3】:

    我同意@Mark Byers 和@tafa 的观点,即直接使用双精度作为键是一个坏主意。如果你想确保你有完全相同的数字,你可以根据构成双精度的字节构建一个字符串键。以下结构将双精度映射到与 8 字节相同的内存空间,因此不需要自定义转换。

    [StructLayout(LayoutKind.Explicit)]
    public struct TestStruct
    {
        [FieldOffset(0)]
        public byte byte1;
        [FieldOffset(1)]
        public byte byte2;
        [FieldOffset(2)]
        public byte byte3;
        [FieldOffset(3)]
        public byte byte4;
        [FieldOffset(4)]
        public byte byte5;
        [FieldOffset(5)]
        public byte byte6;
        [FieldOffset(6)]
        public byte byte7;
        [FieldOffset(7)]
        public byte byte8;
    
        [FieldOffset(0)]
        public double double1;
    }
    

    然后可以将它包装在这样的函数中(假设您在类中将结构定义为私有变量)

    static string GetStringKey(double key)
    {
        _conversionStruct.double1 = Double.MaxValue;
    
        return String.Format("{0}:{1}:{2}:{3}:{4}:{5}:{6}:{7}", 
            _conversionStruct.byte1,
            _conversionStruct.byte2, 
            _conversionStruct.byte3, 
            _conversionStruct.byte4, 
            _conversionStruct.byte5,
            _conversionStruct.byte6, 
            _conversionStruct.byte7, 
            _conversionStruct.byte8);
    }
    

    并像这样使用。

    var s1 = GetStringKey(double.MaxValue);
    var s2 = GetStringKey(double.MinValue);
    

    这给了...

    s1="255:255:255:255:255:255:239:127" 
    s2="255:255:255:255:255:255:239:255"
    

    【讨论】:

      【解决方案4】:
      • 如果可以,请将双精度数设置为长,并将其用作键。 (乘以 10 的倍数去掉小数点)
      • 另一个不如第一个的选项是将双精度转换为字符串。

      【讨论】:

      • 不确定;我认为它会起作用,但我认为它在速度方面不是最好的
      猜你喜欢
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 2010-11-13
      • 1970-01-01
      • 2011-01-24
      • 1970-01-01
      • 1970-01-01
      • 2020-04-02
      相关资源
      最近更新 更多