我想要从一个字符串中生成一个0-9的数字。生成的数字不必可预测,但同一个字符串必须始终生成相同的数字。
我的初始想法是只需使用string.GetHashCode()并取最后一位数字即可。
如果我这样做,那么(a)我是否保证总是得到相同的数字,(b)我是否会在0-9之间获得合理均匀分布的数字?
或者,有没有更好的方法来实现我的目标?
public static long GetDeterministicId(string m)
{
return (long) m.ToCharArray().Select((c, i) => Math.Pow(i, c%5)*Math.Max(Math.Sqrt(c), i)).Sum();
}
编辑
如果您只需要0-9之间的数字,则可以通过取模10来进一步处理:
public static long GetDeterministicId(string m)
{
return (longg) m.ToCharArray().Select((c, i) => Math.Pow(i, c%5)*Math.Max(Math.Sqrt(c), i)).Sum() % 10;
}
0 -> 156
1 -> 163
3 -> 114
7 -> 79
6 -> 72
9 -> 55
2 -> 128
8 -> 45
5 -> 89
4 -> 99
这并不完美,但还可以。
编辑2
进一步测试表明,将第一个模数替换为8(即Math.Pow(i, c%8)*
)可以产生更好的分布:
0 -> 95
1 -> 113
2 -> 148
3 -> 91
4 -> 68
5 -> 92
6 -> 119
7 -> 79
8 -> 99
9 -> 96
编辑 3
好的,获胜者是
return (int)m.ToCharArray().Select((c, i) => Math.Pow(i+2, c % 8) * Math.Max(Math.Sqrt(c), i+2)).Sum() % 10;
而 0-9 的分布为
0 -> 90
1 -> 96
2 -> 100
3 -> 99
4 -> 97
5 -> 106
6 -> 110
7 -> 90
8 -> 103
9 -> 109
这足够接近均匀分布!
string strEntry = "lol"; //Your String Here
int intNum = (int)strEntry[strEntry.Length - 1]; //To Convert last letter to its numeric equivalent. Jeppe Stig Nielsen's suggestion
intNum = int.Parse(intNum.ToString().Substring(intNum.ToString().Length - 1)); //Get the last digit of the number you got from previous step
你得到的数字一定是从0到9之间的一个数字,并且始终相同。另外,我想你也很容易理解代码在做什么。
或者...你可以使用稍微高级一点的方法,它只是将字符串中每个字母的数值相加,然后返回该值的最后一位数字:
string strEntry = "lol";
List<int> intList = new List<int>();
foreach (char c in strEntry)
{
intList.Add((int)c);
}
int intNum = intList.Sum();
intNum = int.Parse(intNum.ToString().Substring(intNum.ToString().Length - 1));
如果你不想仅仅使用上面第二个选项中提供的最后一位数字……你可以这样做:
string strEntry = "lol";
List<int> intList = new List<int>();
foreach (char c in strEntry)
{
intList.Add((int)c);
}
int intNum = intList.Sum();
while (intNum.ToString().Length != 1)
{
intList.Clear();
foreach (char c in intNum.ToString())
{
intList.Add(int.Parse(c.ToString()));
}
intNum = intList.Sum();
}
//You can just get the number you required from intNum
strEntry
的最后一个字符(即最后一个UTF-16 代码单元),更容易使用索引器,因此可以使用以下代码:int intNum = strEntry[strEntry.Length - 1];
。 - Jeppe Stig Nielsen有很多方法可以实现这个功能。例如,您可以取所有字符的总和除以10的余数。
public static int HashString(string str)
{
if(string.IsNullOrEmpty(str)) return 0;
return str.ToCharArray().Sum(c => (int)c) % 10;
}
public static int CheckSum(string s)
{
int sum = 0;
foreach (char c in s)
{
sum = (sum + c)%10;
}
return sum;
}
GetHashCode
方法的一致性。 - theBstring.GetHashCode
,但这种复杂的操作并没有太多意义,您只是想从0-9范围内获取哈希值,这将在任何情况下都会产生大量碰撞。因此,例如,您可以只取字符串的第一个字节,并取其十进制表示中的第一个数字,或者对字符串长度执行相同的操作。 - Ilia MaskovGetHashCode
在你的应用程序 进程 的生命周期内肯定是“一致”的(即对于具有相同字符串值的每个string
实例,都会返回相同的值)。因此,在应用程序运行期间,给定字符串值的哈希是固定的。如果不是这种情况,GetHashCode
将无用. 但是:如果您退出进程,将 .NET Framework 更新为新版本,然后再次启动应用程序,则该字符串值在新的 BCL 版本下可能具有不同的哈希值。 - Jeppe Stig Nielsen