将字母字符串转换为数字并递归求和,使它们低于某个最大值

Convert an alphabetic string into digits and recursively sum them so they're below a certain max

本文关键字:最大值 于某个 求和 递归 字符串 转换 数字      更新时间:2023-09-26

这是一个算术难题给你StackOverflowers。我正在制作一款JS游戏,允许玩家输入自己的名字,并根据他们输入的内容生成另一个名字。有点像这样。基本上,每次有人输入一个特定的字符串时,我都希望通过从列表中获取项来生成相同的其他字符串。

我有一个单词数组,在这个例子中编号为20

"nouns": [
    "Nitwit",
    "Cretin",
    "Village Idiot"
    // ..
]

当用户输入他们的名字时,我将每个ASCII字母字符转换为一个数字。我将把所有结果的数字加起来,并使用总数从数组中选择一个单词。

// Convert alpha chars to numerical equivalents
function str2num (mystr) {
    mystr = mystr.toUpperCase();
    var conv = [],
        l = mystr.length,
        regex = /^[A-Za-z]+$/;
    for (var i = 0; i < l; i++) {
        if (regex.test(mystr.charAt(i))) {
            conv.push(mystr.charCodeAt(i) - 64);
        }
    }
    var c = conv.length,
        sum = 0;
    for (var j = 0; j < c; j++) {
        sum += conv[j];
    }
    return sumDigits(sum);
}

由于单词数组中只有20个元素,所以我总是希望总和小于20。如果它等于或大于20,我要把它的数字加起来。这是我目前正在做的。

// Recursively add digits of number together
// till the total is less than length of word list
function sumDigits (number) {
    var listLength = adjectives.length;
    var sum = number % listLength;
    if (number > listLength) {
        var remainder = Math.floor(number / 10);
        sum += sumDigits(remainder);
    }
    if (sum > listLength) {
        sum = sumDigits(sum);
    }
    return sum;
}

当我得到的结果低于20时,我将nouns[sum]的值返回给用户。这段代码非常有效——得到的总和总是低于允许的最大值。但结果并不是很随机——似乎我得到的和在0到20范围的下端不成比例。我不希望用户总是看到列表开头的单词。我是否可以对sumDigits进行任何更改,以确保结果的均匀分布?还是已经正确了?(我做这个JSFiddle是为了演示我所说的内容)

我会让它依赖于名称中字符的字符码:

function getValue(name) {
    var letters = name.toLowerCase().split(''), 
        value = 0,
        i = 0;
    for(; i < letters.length; i ++) {
        value += letters[i].charCodeAt(0);
    }
    return value % 20;
}

当前实现中的输出和确实是不是均匀分布的。

作为一个例子,考虑所有有一个或两个数字的数字(1 - 99):

1 of them is  summed up to  1 ( 1)
2 of them are summed up to  2 ( 2, 20)
3 of them are summed up to  3 ( 3, 30, 21)
4 of them are summed up to  4 ( 4, 40, 31, 22)
5 of them are summed up to  5 ( 5, 50, 41, 32, 23)
6 of them are summed up to  6 ( 6, 60, 51, 42, 33, 24)
7 of them are summed up to  7 ( 7, 70, 61, 52, 43, 34, 25)
8 of them are summed up to  8 ( 8, 80, 71, 62, 53, 44, 35, 26)
9 of them are summed up to  9 ( 9, 90, 81, 72, 63, 54, 45, 36, 27)
9 of them are summed up to 10 (10, 91, 82, 73, 64, 55, 46, 37, 28)
9 of them are summed up to 11 (11, 92, 83, 74, 65, 56, 47, 38, 29)
8 of them are summed up to 12 (12, 93, 84, 75, 66, 57, 48, 39)
7 of them are summed up to 13 (13, 94, 85, 76, 67, 58, 49)
6 of them are summed up to 14 (14, 95, 86, 77, 68, 59)
5 of them are summed up to 15 (15, 96, 87, 78, 69)
4 of them are summed up to 16 (16, 97, 88, 79)
3 of them are summed up to 17 (17, 98, 89)
2 of them are summed up to 18 (18, 99)
1 of them is  summed up to 19 (19)

这可能更接近正态分布而不是均匀分布

为了实现后者,只需返回sum % c而不是sumDigits(sum)

我认为sumDigits函数返回一个有偏的数。不返回sumDigits(sum)。您可以返回sum % 20

fzzle的回答很好。

或者,您可以使用while进行求和约简:

var reduced = sum;
while(reduced > 20){
    reduced -= name.length;
}

这是一个更完整的例子:

var sum = 0;
var name = 'John Smith'.split('');
for(var k in name){
    sum += name[k].charCodeAt(0);
}
var key = sum;
while(key > 20){
    key -= 'John Smith'.length;
}

如果你测试它,你会看到它产生了不同的结果sumDigits % 20。请注意,我不知道对于异常长的名称,这个方法将如何表现。让我测试一下。

确认。XD我尝试了John Smith John Smith John Smith John Smithxx,打破了它。不要认为这是一个答案。(