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

问题描述

简单的例子: 以英语初学者(范围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

我的功能有两个主要问题:

  • 即使我使用正数进行运算,编译器返回答案也要花费一些时间,因此恐怕这是一个非常耗时的操作,可以更轻松地进行整理。
  • 我的函数方法不适用于负数。我非常清楚什么是未定义的偏移量,它无法访问数组的负索引。我只是不知道如何使模运算符向后工作...

任何帮助解决此问题的人都会由衷的感谢。

解决方法

请执行以下操作:

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

    return chr(65 + $newOrd);
}

它只是在新字母的序数值上使用模26,相对于字母A(65)。如果

Demo

,

取26为模是正确的想法。

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

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


因此,代码很简单。

  • 对数字应用模26。
  • 获取当前char的ascii值,并在其中添加“数字”。
  • 如果新的ascii值在65到90之间,则返回char值。
  • 如果新的ascii值超过90,则使用偏移量直到90,然后返回其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

,

Jeto的方法得到了改进,可以使用大写或小写字母返回正确答案:

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",PHP_EOL;
echo getNewLetter("h",-4),26),27),-26),-27),PHP_EOL;
echo PHP_EOL;
echo getNewLetter("a",-2),PHP_EOL;
echo getNewLetter("A",PHP_EOL;
echo getNewLetter("b",-3),PHP_EOL;
echo getNewLetter("B",PHP_EOL;
echo PHP_EOL;
echo getNewLetter("Z",2),PHP_EOL;
echo getNewLetter("Z",PHP_EOL;
echo PHP_EOL;
echo getNewLetter("A",-1),PHP_EOL;