在一个方向或另一个方向多次移动 PHP 数组的最有效方法是什么?

What is the most efficient way to move through a PHP array a number of times in one direction or another?

简单的例子: 以英语基础(范围 A-Z)作为参考。如果给我一个字母 - 比方说 'a' - 和一个数字 - 比方说'2' - 我需要找出字母 2 的位置。 答案是 'c' ('a'--> 1 步:'b' --> 2 步:'c')

当然,你可以得到一个大于字母大小的数字,即 26。由于规则是字母 z 之后再次出现字母 a,这意味着如果在前面的示例中数字 26传递给我们需要找到的字母是 'a'.

该问题的最后一种情况是您可能收到一个负数。因此,如果字母 'a' 与数字 '-3' 一起提供,答案将是 'x' ('a'--> 1 步:'z' --> 2 步:'y' --> 3步:'x').

这是我目前的代码:

function getNewLetter($letter, $number) {

    $letters = range('A', 'Z');

    if ($number >= 0) {
        return $letters[($number + array_search($letter, $letters) % 26)%26];
    } else {
        return $letters[($number - (array_search($letter, $letters) % 26))%26];
    }
}

echo getNewLetter("H", 4);      // correctly prints out L
echo getNewLetter("H", 26);       // correctly prints out H
echo getNewLetter("H", -4);     // throws undefined offset -11 error

我的函数有两个主要问题:

任何帮助解决这个问题的人都将由衷地感谢你。

取模 26 是一个正确的想法。

这是因为,1 的偏移量与 27 的偏移量相同。 0 的偏移量与偏移量 2652 等相同,依此类推。

对负数取模 26 也应用相同的逻辑,因为 -27 的旋转与 -1 的旋转相同。


所以,代码很简单。

  • 对数字应用模 26。
  • 获取当前字符的 ascii 值并向其添加“数字”。
  • 如果新的 ascii 值在 65 和 90 之间,return char 值。
  • 如果新的 ascii 值超过 90,则使用偏移量直到 90 和 return 它的 chr() + 64。如果值低于 65,反之亦然。

片段:

function getNewLetter($letter, $number) {
    $number = $number % 26;
    $new_ascii_value = ord($letter) + $number;
    if($new_ascii_value < 65){
        $number = abs($number) - (ord($letter) - 65);
        return chr(91 - $number);
    }else if($new_ascii_value >= 91){
        return chr(64 + ($new_ascii_value - 90));
    }
    return chr($new_ascii_value);
}

演示: https://3v4l.org/0Yhkm

下面应该这样做:

function getNewLetter(string $letter, int $number): string
{
    $newOrd = (ord($letter) + $number - 65) % 26;
    if ($newOrd < 0) {
        $newOrd += 26;
    }

    return chr(65 + $newOrd);
}

它只是对新字母相对于字母 A (65) 的序数值使用模 26。如果它小于 0,它会再次添加 26 以“修复”它。

Demo

Jeto 的方法改进为 return 大写或小写字母的正确答案:

function getNewLetter(string $letter, int $number): string {

    $movement = $letter < 'a' ? 65 : 97;      // Depending on case, letter 'a' starts at different numbers of ASCII table

    $newOrd = (ord($letter) + $number - $movement) % 26;
    if ($newOrd < 0) {
        $newOrd += 26;
    }

    return chr($movement + $newOrd);
}

这里有一些通过的测试来尝试这个方法:

echo getNewLetter("h", 4), PHP_EOL;
echo getNewLetter("H", 4), PHP_EOL;
echo getNewLetter("h", -4), PHP_EOL;
echo getNewLetter("H", -4), PHP_EOL;
echo getNewLetter("h", 26), PHP_EOL;
echo getNewLetter("H", 26), PHP_EOL;
echo getNewLetter("H", 27), PHP_EOL;
echo getNewLetter("H", -26), PHP_EOL;
echo getNewLetter("H", -27), PHP_EOL;
echo PHP_EOL;
echo getNewLetter("a", -2), PHP_EOL;
echo getNewLetter("A", -2), PHP_EOL;
echo getNewLetter("b", -3), PHP_EOL;
echo getNewLetter("B", -3), PHP_EOL;
echo PHP_EOL;
echo getNewLetter("Z", 2), PHP_EOL;
echo getNewLetter("Z", 26), PHP_EOL;
echo getNewLetter("Z", 27), PHP_EOL;
echo getNewLetter("Z", -26), PHP_EOL;
echo getNewLetter("Z", -27), PHP_EOL;
echo PHP_EOL;
echo getNewLetter("A", -1), PHP_EOL;
echo getNewLetter("A", -27), PHP_EOL;