PHP:从非索引值开始,查找数组中的下一个可用值

5

我已经被这个 PHP 问题难住了一整天。基本上,我们有一个按 24 小时格式排列的小时数组以及一个任意值($hour)(也是 24 小时格式)。问题是,我们需要取出 $hour,并从数组中找到下一个可用的值,从紧接着 $hour 的值开始。

该数组可能如下所示:

$goodHours = array('8,9,10,11,12,19,20,21).

那么小时值可能是:

$hour = 14;

所以,我们需要一种方法来确定19是下一个最佳时间。此外,我们可能还需要获取第二个、第三个或第四个(等等)可用值。
问题似乎在于,由于14不是数组中的值,因此没有索引可以引用,让我们增加到下一个值。
为了简化事情,我已经取出了$goodHours并重复了多次这些值,这样我就不必处理回到开始的问题(也许不是最好的方法,但是一个快速的解决方案)。
我感觉我错过了一些简单的东西,但如果有人能帮我澄清一下,我会非常感激。
Erik
5个回答

4
你可以使用for循环来遍历数组,直到找到第一个大于你搜索的元素为止:
$goodHours = array(8,9,10,11,12,19,20,21);
$hour = 14;

$length = count($goodHours);
for ($i = 0 ; $i < $length ; $i++) {
    if ($goodHours[$i] >= $hour) {
        echo "$i => {$goodHours[$i]}";
        break;
    }   
}

我可以为您提供:

5 => 19



如果你想要获取你搜索的项目以及之后的一些项目,你可以使用以下类似的代码:

$goodHours = array(8,9,10,11,12,19,20,21);
$hour = 14;
$numToFind = 2;

$firstIndex = -1;
$length = count($goodHours);
for ($i = 0 ; $i < $length ; $i++) {
    if ($goodHours[$i] >= $hour) {
        $firstIndex = $i;
        break;
    }   
}

if ($firstIndex >= 0) {
    $nbDisplayed = 0;
    for ($i=$firstIndex ; $i<$length && $nbDisplayed<$numToFind ; $i++, $nbDisplayed++) {
        echo "$i => {$goodHours[$i]}<br />";
    }
}

这将会给你以下输出结果:
5 => 19
6 => 20

基本上,这里的想法是:
  • 向前移动数组,直到找到第一个>=你要查找的项目
    • 当找到时退出第一个循环
  • 如果找到了匹配的项
    • 在数组上循环,直到其结束或者找到所需数量的项。

3
你还可以使用SPL FilterIterator。尽管它不是最快的解决方案,但它有一个优点,就是你可以在某个地方/任何地方“准备”迭代器,然后将其传递给一个不必知道迭代器内部工作方式的函数/方法,也就是说,下一次你可以传递完全不同的迭代器。
class GreaterThanFilterIterator extends FilterIterator {
  protected $threshold;
  public function __construct($threshold, Iterator $it) {
    $this->threshold = $threshold;
    parent::__construct($it);
  }

  public function accept() {
    return $this->threshold < parent::current();
  }
}

function doSomething($it) {
  // no knowledge of the FilterIterator here
  foreach($it as $v) {
    echo $v, "\n";
  }
}

$goodHours = array(8,9,10,11,12,19,20,21);
$it = new GreaterThanFilterIterator(14, new ArrayIterator($goodHours));
doSomething($it);

打印

19
20
21

1

由于$goodHours已经排序,这很容易:

$next = 0;
foreach($goodHours as $test)
   if($test > $hour && $next = $test)
       break;

在那个四行代码之后(当然可以用更少的行数编写),$next 的值要么是0,如果$hour 无法匹配 $goodHours,要么它包含紧接着 $hour 的值。这就是你所要求的。

这仅在$goodHours已排序的情况下有效,如果没有排序,您可以使用asort()函数进行排序。


0

尝试使用这个函数:

function nextValueGreaterThan($haystack, $needle, $n=1) {
    sort($haystack);
    foreach ($haystack as $val) {
        if ($val >= $needle) {
            $n--;
            if ($n <= 0) {
                return $val;
            }
        }
    }
}

$goodHours = array(8,9,10,11,12,19,20,21);
echo nextValueGreaterThan($goodHours, 14);     // 19
echo nextValueGreaterThan($goodHours, 14, 3);  // 21

0

这里有一个类似于其他答案的解决方案,包括一个可选的“偏移”参数,可以获取第n个项目,距离事实上的第一个项目。

class GoodHours {
  private $hours = array(8,9,10,11,12,19,20,21);

  public function getGoodHour($hour, $offset = 0) {
    $length = count($this->hours);
    for ($i = 0 ; $i < $length && $this->hours[$i] < $hour ; $i++)
      ; // do nothing
    return $this->hours[($i + $offset) % $length];
  }
}

// some test values

$good = new GoodHours();
$x = $good->getGoodHour(5);    // 8
$x = $good->getGoodHour(5,1);  // 9
$x = $good->getGoodHour(5,2);  // 10
$x = $good->getGoodHour(10);   // 10
$x = $good->getGoodHour(10,1); // 11
$x = $good->getGoodHour(10,2); // 12
$x = $good->getGoodHour(21);   // 21
$x = $good->getGoodHour(21,1); // 8
$x = $good->getGoodHour(21,2); // 9
$x = $good->getGoodHour(21);   // 8
$x = $good->getGoodHour(22,1); // 9
$x = $good->getGoodHour(22,2); // 10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接