如何从C#中的字符串生成非随机数?

时间:2015-09-04 14:24:52

标签: c# .net

我想取一个字符串并从0-9生成一个数字。我得到的数字不是必须可预测的,但相同的字符串必须始终生成相同的数字。

我最初的想法是只做string.GetHashCode()并从代码中取最后一位数字。

如果我这样做,我(a)是否会保证总是以相同的数字为同一个字符串结束,并且我(b)最终会在0-9之间合理均匀地分配数字?

或者,是否有更好的方法来实现我想要的目标?

4 个答案:

答案 0 :(得分:8)

这应该可以解决问题 - 我将此用于 deterministic 模拟:

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,那么进一步mod数字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;
}

我已经用英语(https://gist.github.com/deekayen/4148741#file-1-1000-txt)运行了1000个最常用的单词,0-9的分布是:

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

足够接近均匀分布!

答案 1 :(得分:2)

对于一种非常“低技术”的方法,哪里不如rbm的回答那么令人印象深刻......你可以这样做:

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

答案 2 :(得分:0)

有很多方法可以实现此功能。例如,您可以将剩下的除法除以所有字符总和的10。

public static int HashString(string str)
{
   if(string.IsNullOrEmpty(str)) return 0;
   return str.ToCharArray().Sum(c => (int)c) % 10;
}

答案 3 :(得分:0)

  

我是否(a)保证总是以相同的数字结束   相同的字符串[?]

没有。正如评论中提到的B,GetHashCode的值是一个实现细节,不一定是consistent,例如跨不同版本的.NET。你最好自己编写自己的函数。

简单校验和怎么样?

public static int CheckSum(string s)
{
    int sum = 0;
    foreach (char c in s)
    {
        sum = (sum + c)%10;
    }
    return sum;
}