PHP:数组中的下一个可用值,以非索引值开头

时间:2022-08-08 21:30:46

I've been stumped on this PHP issue for about a day now. Basically, we have an array of hours formatted in 24-hour format, and an arbitrary value ($hour) (also a 24-hour). The problem is, we need to take $hour, and get the next available value in the array, starting with the value that immediately proceeds $hour.

我已经被困在这个PHP问题上大约一天了。基本上,我们有一个小时数组,格式为24小时格式,任意值($小时)(也是24小时)。问题是,我们需要花费$ hour,并获得数组中的下一个可用值,从立即进行$ hour的值开始。

The array might look something like:

该数组可能类似于:

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

Then the hour value might be:

那么小时值可能是:

$hour = 14;

So, we need some way to know that 19 is the next best time. Additionally, we might also need to get the second, third, or fourth (etc) available value.

所以,我们需要一些方法来知道19是下一个最好的时间。此外,我们可能还需要获得第二个,第三个或第四个(等)可用值。

The issue seems to be that because 14 isn't a value in the array, there is not index to reference that would let us increment to the next value.

问题似乎是因为14不是数组中的值,所以没有引用的索引可以让我们递增到下一个值。

To make things simpler, I've taken $goodHours and repeated the values several times just so I don't have to deal with going back to the start (maybe not the best way to do it, but a quick fix).

为了简单起见,我已经花了好几个小时并重复了几次这样的值,所以我不必处理回到开始(也许不是最好的方法,但快速修复)。

I have a feeling this is something simple I'm missing, but I would be so appreciative if anyone could shed some light.

我有一种感觉,这是一件很简单的事情,我很想念,但如果有人能说清楚,我会非常感激。

Erik

5 个解决方案

#1


4  

You could use a for loop to iterate over the array, until you find the first that is greater than the one you're searching :

您可以使用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;
    }   
}

Would give you :

会给你:

5 => 19



And, to get the item you were searching for, and some after that one, you could use something like this :

并且,要获得您正在搜索的项目,以及在该项目之后的某些项目,您可以使用以下内容:

$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 />";
    }
}

Which would give you the following output :

哪个会给你以下输出:

5 => 19
6 => 20


Basically, here, the idea is to :

基本上,这里的想法是:

  • advance in the array, until you find the first item that is >= to what you are looking for
    • get out of that first loop, when found
    • 找到后退出第一个循环

  • 在数组中前进,直到找到第一个项目> =到你想要的东西离开第一个循环,找到

  • If a matching item was found
    • loop over the array, until either its end,
    • 循环遍历数组,直到其结束,

    • or you've found as many items as you were looking for.
    • 或者你找到了和你想要的一样多的物品。

  • 如果找到一个匹配的项目循环遍历数组,直到它的结束,或者你找到了你想要的那么多的项目。

#2


3  

You can also use the SPL FilterIterator. Though it's not the fastest solution there is, it has the advantage that you can "prepare" the iterator somewhere/anywhere and then pass it to a function/method that doesn't have to know how the iterator works on the inside, i.e. you could pass a completely different iterator the next time.

您也可以使用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);

prints

19
20
21

#3


1  

As $goodHours is already sorted, that's something easy:

由于$ goodHours已经排序,这很简单:

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

After that four-liner (that can be written in a smaller number of lines naturally), $next is either 0 if $hour could not be matched in $goodHours or it contains the value that immediately proceeds $hour. That is what you asked for.

在那个四线(可以自然地用较少数量的线写入)之后,如果在$ goodHours中无法匹配$ hour或者它包含立即进行$ hour的值,则$ next为0。这就是你要求的。

This only works when $goodHours is sorted, in case it's not, you can sort it by using the asort() function.

这仅在$ goodHours排序时有效,如果不是,则可以使用asort()函数对其进行排序。

#4


0  

Try this function:

试试这个功能:

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

#5


0  

Here's an answer similar to the rest of these, including an optional "offset" parameter, that gets your n'th item past the de-facto first one.

这是一个类似于其余部分的答案,包括一个可选的“偏移”参数,它使你的第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

#1


4  

You could use a for loop to iterate over the array, until you find the first that is greater than the one you're searching :

您可以使用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;
    }   
}

Would give you :

会给你:

5 => 19



And, to get the item you were searching for, and some after that one, you could use something like this :

并且,要获得您正在搜索的项目,以及在该项目之后的某些项目,您可以使用以下内容:

$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 />";
    }
}

Which would give you the following output :

哪个会给你以下输出:

5 => 19
6 => 20


Basically, here, the idea is to :

基本上,这里的想法是:

  • advance in the array, until you find the first item that is >= to what you are looking for
    • get out of that first loop, when found
    • 找到后退出第一个循环

  • 在数组中前进,直到找到第一个项目> =到你想要的东西离开第一个循环,找到

  • If a matching item was found
    • loop over the array, until either its end,
    • 循环遍历数组,直到其结束,

    • or you've found as many items as you were looking for.
    • 或者你找到了和你想要的一样多的物品。

  • 如果找到一个匹配的项目循环遍历数组,直到它的结束,或者你找到了你想要的那么多的项目。

#2


3  

You can also use the SPL FilterIterator. Though it's not the fastest solution there is, it has the advantage that you can "prepare" the iterator somewhere/anywhere and then pass it to a function/method that doesn't have to know how the iterator works on the inside, i.e. you could pass a completely different iterator the next time.

您也可以使用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);

prints

19
20
21

#3


1  

As $goodHours is already sorted, that's something easy:

由于$ goodHours已经排序,这很简单:

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

After that four-liner (that can be written in a smaller number of lines naturally), $next is either 0 if $hour could not be matched in $goodHours or it contains the value that immediately proceeds $hour. That is what you asked for.

在那个四线(可以自然地用较少数量的线写入)之后,如果在$ goodHours中无法匹配$ hour或者它包含立即进行$ hour的值,则$ next为0。这就是你要求的。

This only works when $goodHours is sorted, in case it's not, you can sort it by using the asort() function.

这仅在$ goodHours排序时有效,如果不是,则可以使用asort()函数对其进行排序。

#4


0  

Try this function:

试试这个功能:

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

#5


0  

Here's an answer similar to the rest of these, including an optional "offset" parameter, that gets your n'th item past the de-facto first one.

这是一个类似于其余部分的答案,包括一个可选的“偏移”参数,它使你的第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