我必须在一些 opaque 矩形区域中绘制一些任意字符串。 我需要那个区域的背景颜色与给定的字符串是唯一的。
说,如果我画“巴黎”和“巴黎1”,他们的颜色应该是不同的。但如果我用蓝色绘制“巴黎”,那么彼此的“巴黎”也应该用蓝色绘制。
我再次强调颜色应该是不透明的。
为此,我找到了一个简单的解决方案:
rectangleBackColor = Color.FromArgb(myString.GetHashCode())
问题在于不透明度。我需要“消除”“A”(alpha)组件。
现在,这样的代码可以正常工作
rectangleBackColor = Color.FromArgb(myString.GetHashCode())
' set the alpha value = 255 for an opaque color '
rectangleBackColor = Color.FromArgb(255, rectangleBackColor)
但它可以松散字符串颜色的唯一性。
说,我有两个不同的hashCodes(在hexa中)x AB 11 22 33
和x FF 11 22 33
。
将AB
设置为FF
我将两个不同的字符串设置为相同的背景颜色(x FF 11 22 33
)。这不好。
答案 0 :(得分:2)
您无法为字符串生成唯一的颜色:
RGB空间具有24位或2 ^ 24-1个唯一值(总共16777215种颜色)。
以下代码将打印16777220个唯一字符串(比颜色数多5个):
for(int i=0; i<16777220 ; ++i) Console.WriteLine(i.ToString());
因此,如果您获取上面编程生成的所有字符串并给出颜色,则必须至少有5个重复颜色的字符串。
顺便说一下,GetHashCode不返回唯一值,只是均匀分布,用32位重复上面的证明(你需要在for循环uint中创建i并将数字更改为4294967295以上,但这些是只有更改)并且您发现无法为32位值(或任何其他固定大小值)中的每个字符串获取唯一值。
你的方法非常好,重复的颜色很少见。
答案 1 :(得分:2)
鉴于您无法生成真正唯一的整数来表示字符串,因为它们可以表示的空间大小不同,您可以尝试:
uint noA = (unit)myString.GetHashCode() / 255;
uint opaque = noA + 0xFF000000;
rectangleBackColor = Color.FromArgb(opaque);
这应该基于哈希码为每个字符串生成(相当)唯一值,并将alpha分量设置为255.显然,这只能生成2 ^ 24个不同的值,因此不是真正唯一的。 / p>
编辑:应该注意,这与您的版本完全相同,但忽略最低8位而不是最高位。
答案 2 :(得分:1)
哈希首先并不是独一无二的。如果您不相信,只需考虑比hashcode多多少个字符串。首先,哈希代码本身就是字符串!这意味着如果您要将不同的哈希代码归属到每个字符串,那么在遍历所有哈希代码之后,您将耗尽哈希代码。
具有相同哈希码的两个字符串称为冲突。对于一个好的哈希码,您可以考虑两个无辜字符串的概率为1 /#{哈希空间的大小}。
另一个不错的属性是,您希望任何截断您的哈希码的行为都是这样的。截断哈希码实际上是正确的做法。
您将获得两个给定名称的碰撞概率约为1 / 16M。 但是,如果你有N字符串,你可能会遇到所谓的birthday problem。 观察至少1次碰撞的概率要大得多。接近N ^ 2 / 16M。
答案 3 :(得分:0)
两个想法:
1)如果在开始着色之前已知所有N个字符串,请计算Perfect Hash(C和C#中的实现)。然后,您可以将每个哈希值乘以256 ^ 3 / N,以在颜色空间上展开结果。
2)如果不知道它们,您可以手动解决冲突。像这样的伪代码:
tries = 5; //arbitrary number
colorcode = myString.GetHashCode()&0xFFFFFF;
while ( Dictionary.containsKey(colorcode ) &&
Dictionary.getValue(colorcode )!= myString &&
tries-->0) {
colorcode = ((colorcode+3) * 92821) &0xFFFFFF; //rehash
}
if (tries) {
Dictionary.insert(colorcode , myString);
}
rectangleBackColor = Color.FromArgb(0xFF000000|colorcode );