在较大的数组上使用 array_shift 速度相当慢。随着数组缩小,速度加快,很可能是因为它必须重新索引较小的数据集。
对于我的目的,我使用了 array_reverse,然后是 array_pop,它不需要重新索引数组,如果需要,它会保留键(在我的情况下无关紧要)。
使用直接索引引用,即 array_test[$i],速度很快,但用于破坏性操作的直接索引引用 + unset 与 array_reverse 和 array_pop 的速度大致相同。它还需要连续的数字键。
(PHP 4, PHP 5, PHP 7, PHP 8)
array_shift — 从数组开头移出元素
array_shift() 将 array
的第一个值移出并返回,缩短 array
一个元素并将所有内容向下移动。所有数字数组键将被修改为从零开始计数,而文字键不会受到影响。
array
输入数组。
返回移出的值,如果 array
为空或不是数组,则返回 null
。
示例 #1 array_shift() 示例
<?php
$stack = array("orange", "banana", "apple", "raspberry");
$fruit = array_shift($stack);
print_r($stack);
?>
以上示例将输出
Array ( [0] => banana [1] => apple [2] => raspberry )
并且 orange
将被赋值给 $fruit。
在较大的数组上使用 array_shift 速度相当慢。随着数组缩小,速度加快,很可能是因为它必须重新索引较小的数据集。
对于我的目的,我使用了 array_reverse,然后是 array_pop,它不需要重新索引数组,如果需要,它会保留键(在我的情况下无关紧要)。
使用直接索引引用,即 array_test[$i],速度很快,但用于破坏性操作的直接索引引用 + unset 与 array_reverse 和 array_pop 的速度大致相同。它还需要连续的数字键。
注意
array_pop() 的复杂度为 O(1)。
array_shift() 的复杂度为 O(n)。
array_shift() 需要对数组进行重新索引过程,因此它必须遍历所有元素并对其进行索引。
只是一个返回带有第一个键和值的简单数组的有用版本。可能还有更好的方法,但它对我有用 ;-)
<?php
function array_kshift(&$arr)
{
list($k) = array_keys($arr);
$r = array($k=>$arr[$k]);
unset($arr[$k]);
return $r;
}
// 在一个简单的关联数组上测试它
$arr = array('x'=>'ball','y'=>'hat','z'=>'apple');
print_r($arr);
print_r(array_kshift($arr));
print_r($arr);
?>
输出
数组
(
[x] => ball
[y] => hat
[z] => apple
)
数组
(
[x] => ball
)
数组
(
[y] => hat
[z] => apple
)
<?php
// 使用 array_pop/shift/push/unshift 操作非连续索引数组时需谨慎:
$shifty = $poppy = array(
2 => '(2)',
1 => '(1)',
0 => '(0)',
); print_r( $shifty );
array_shift( $shifty ); print_r( $shifty );
// [0] => (1)
// [1] => (0)
array_pop( $poppy ); print_r( $poppy );
// [2] => (2)
// [1] => (1)
$shifty = $poppy = array(
'a' => 'A',
'b' => 'B',
'(0)',
'(1)',
'c' => 'C',
'd' => 'D',
); print_r( $shifty );
array_shift( $shifty ); print_r( $shifty );
// [b] => B
// [0] => (0)
// [1] => (1)
// [c] => C
// [d] => D
array_unshift( $shifty, 'unshifted'); print_r( $shifty );
// [0] => unshifted
// [b] => B
// [1] => (0)
// [2] => (1)
// [c] => C
// [d] => D
array_pop( $poppy ); print_r( $poppy );
// [a] => A
// [b] => B
// [0] => (0)
// [1] => (1)
// [c] => C
array_push( $poppy, 'pushed'); print_r( $poppy );
// [a] => A
// [b] => B
// [0] => (0)
// [1] => (1)
// [c] => C
// [2] => pushed
?>
如前所述,在 PHP4 中,array_shift() 通过引用修改输入数组,但它不通过引用返回第一个元素。这看起来可能非常出乎意料。如果您正在处理引用集合(在我的例子中是 XML 节点),则此方法应该可以解决问题。
<?php
/**
* 此函数与 array_shift() 的行为相同,除了
* 它返回对数组第一个元素的引用,而不是副本。
*
* @param array &$array
* @return mixed
*/
function &array_shift_reference(&$array)
{
if (count($array) > 0)
{
$key = key($array);
$first =& $array[$key];
}
else
{
$first = null;
}
array_shift($array);
return $first;
}
class ArrayShiftReferenceTest extends UnitTestCase
{
function testFunctionRemovesFirstElementOfNumericallyIndexedArray()
{
$input = array('foo', 'bar');
array_shift_reference($input);
$this->assertEqual(array('bar'), $input, '%s: 数组应该向左移动一个元素');
}
function testFunctionRemovesFirstElementOfAssociativeArray()
{
$input = array('x' => 'foo', 'y' => 'bar');
array_shift_reference($input);
$this->assertEqual(array('y' => 'bar'), $input, '%s: 数组应该向左移动一个元素');
}
function testFunctionReturnsReferenceToFirstElementOfNumericallyIndexedArray()
{
$foo = 'foo';
$input = array(&$foo, 'bar');
$first =& array_shift_reference($input);
$this->assertReference($foo, $first, '%s: 返回值应引用第一个数组元素');
}
function testFunctionReturnsReferenceToFirstElementOfAssociativeArray()
{
$foo = 'foo';
$input = array('x' => &$foo, 'y' => 'bar');
$first =& array_shift_reference($input);
$this->assertReference($foo, $first, '%s: 返回值应引用第一个数组元素');
}
function testFunctionReturnsNullIfEmptyArrayPassedAsInput()
{
$input = array();
$first = array_shift_reference($input);
$this->assertNull($first, '%s: 数组没有第一个元素,因此应返回 NULL');
}
}
?>
从数组中间移除一个元素(类似于 array_shift,只是我们想要移除中间的元素而不是第一个元素,并将后续的所有键向下移动一个位置)
请注意,这仅适用于枚举数组。
<?php
$array = array('a', 'b', 'c', 'd', 'e', 'e');
/*
array(6) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
string(1) "c"
[3]=>
string(1) "d"
[4]=>
string(1) "e"
[5]=>
string(1) "e"
}
*/
$indexToRemove = 2;
unset($array[$indexToRemove]);
$array = array_slice($array, 0);
/*
array(5) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
string(1) "d"
[3]=>
string(1) "e"
[4]=>
string(1) "e"
}
*/
?>
希望这对某些人有所帮助!
此 removeAdd 函数,第一个参数将数组左移,然后将第二个参数左插到数组中。第一个参数是数组,第二个参数可以是整数或字符串。
<?php
function removeAdd ($arr, $newer){
$a = array_shift($arr);
$b = array_unshift($arr, $newer);
foreach ($arr as $value){
echo $value."<br />";
}
}
$a = array(1,2,3,4,5,6);
foreach ($a as $current){
echo $current."<br />";
}
echo "<hr />";
removeAdd($a, 0);
?>
输出
1
2
3
4
5
6
_______
0
2
3
4
5
6
对于那些可能尝试对包含引用的数组使用 array_shift() 的人(例如,使用链接节点树),请注意 array_shift() 可能无法按预期工作:它将返回数组第一个元素的*副本*,而不是元素本身,因此您的引用将丢失。
解决方案是在使用 array_shift() 删除之前引用第一个元素。
<?php
// 只使用 array_shift:
$a = 1;
$array = array(&$a);
$b =& array_shift($array);
$b = 2;
echo "a = $a, b = $b<br>"; // 输出 a = 1, b = 2
// 解决方案:首先引用第一个元素:
$a = 1;
$array = array(&$a);
$b =& $array[0];
array_shift($array);
$b = 2;
echo "a = $a, b = $b<br>"; // 输出 a = 2, b = 2
?>
如果您想获取顶部元素并在之后旋转数组,这里有一个小函数。
function array_rotate(&$arr)
{
$elm = array_shift($arr);
array_push($arr, $elm);
return $elm;
}
此函数将保存数组的键值,并且它将在较低版本的 PHP 中工作。
<?php
function array_shift2(&$array){
reset($array);
$key = key($array);
$removed = $array[$key];
unset($array[$key]);
return $removed;
}
?>
这是一个用于解析命令行参数的实用程序函数。
<?php
/**
* CommandLine 类
*
* @package Framework
*/
/**
* 命令行界面 (CLI) 实用程序类。
*
* @author Patrick Fisher <[email protected]>
* @since 2009 年 8 月 21 日
* @package Framework
* @subpackage Env
*/
class CommandLine {
/**
* 解析参数
*
* [pfisher ~]$ echo "<?php
* > include('CommandLine.php');
* > \$args = CommandLine::parseArgs(\$_SERVER['argv']);
* > echo "\n", '\$out = '; var_dump(\$args); echo "\n";
* > ?>" > test.php
*
* [pfisher ~]$ php test.php plain-arg --foo --bar=baz --funny="spam=eggs" --alsofunny=spam=eggs \
* > 'plain arg 2' -abc -k=value "plain arg 3" --s="original" --s='overwrite' --s
*
* $out = array(12) {
* [0] => string(9) "plain-arg"
* ["foo"] => bool(true)
* ["bar"] => string(3) "baz"
* ["funny"] => string(9) "spam=eggs"
* ["alsofunny"] => string(9) "spam=eggs"
* [1] => string(11) "plain arg 2"
* ["a"] => bool(true)
* ["b"] => bool(true)
* ["c"] => bool(true)
* ["k"] => string(5) "value"
* [2] => string(11) "plain arg 3"
* ["s"] => string(9) "overwrite"
* }
*
* @author Patrick Fisher <[email protected]>
* @since 2009 年 8 月 21 日
* @see https://php.net/manual/en/features.commandline.php
* #81042 function arguments($argv) by technorati at gmail dot com, 12-Feb-2008
* #78651 function getArgs($args) by B Crawford, 22-Oct-2007
* @usage $args = CommandLine::parseArgs($_SERVER['argv']);
*/
public static function parseArgs($argv){
array_shift($argv);
$out = array();
foreach ($argv as $arg){
// --foo --bar=baz
if (substr($arg,0,2) == '--'){
$eqPos = strpos($arg,'=');
// --foo
if ($eqPos === false){
$key = substr($arg,2);
$value = isset($out[$key]) ? $out[$key] : true;
$out[$key] = $value;
}
// --bar=baz
else {
$key = substr($arg,2,$eqPos-2);
$value = substr($arg,$eqPos+1);
$out[$key] = $value;
}
}
// -k=value -abc
else if (substr($arg,0,1) == '-'){
// -k=value
if (substr($arg,2,1) == '='){
$key = substr($arg,1,1);
$value = substr($arg,3);
$out[$key] = $value;
}
// -abc
else {
$chars = str_split(substr($arg,1));
foreach ($chars as $char){
$key = $char;
$value = isset($out[$key]) ? $out[$key] : true;
$out[$key] = $value;
}
}
}
// plain-arg
else {
$value = $arg;
$out[] = $value;
}
}
return $out;
}
}
?>
// 我想删除数组内部的第一个数组
// 但对我来说不起作用:array_shift();
$cargo_file =
数组
(
[0] => 数组
(
[0] => 国家
[1] => 国家代码
[2] => 城市
[3] => 城市其他语言
[4] => 邮政编码
[5] => 天数
)
[1] => 数组
(
[0] => 土耳其
[1] => TR
[2] => 伊斯坦布尔
[3] => 伊斯坦布尔
[4] => 34930
[5] => 9
)
)
$cargo_file = array_shift($cargo_file);
echo "<pre>";
print_r($cargo_file);
echo "</pre>";
// 结果之后
/*
数组
(
[0] => 国家
[1] => 国家代码
[2] => 城市
[3] => 城市其他语言
[4] => 邮政编码
[5] => 天数
)
*/
我开发了一个解决方案
function removeFirstArray($array){
$new_array = [];
foreach ($array as $key => $value) {
if($key > 0){
$new_array[] = $value;
}
}
return $new_array;
}
$cargo_file= removeFirstArray($cargo_file);
echo "<pre>";
print_r($cargo_file);
echo "</pre>";
数组
(
[0] => 数组
(
[0] => 土耳其
[1] => TR
[2] => 伊斯坦布尔
[3] => 伊斯坦布尔
[4] => 34930
[5] => 9
)
)
<?php
//----------------------------------------------------------
// array_shift/array_unshift 的组合
// 极大地简化了我为生成相对路径而创建的一个函数。
// 在我找到它们之前,该算法非常混乱,包含多个
// if 测试、长度计算、嵌套循环等。
// 非常棒的函数。
//----------------------------------------------------------
function create_relative_path($inSourcePath, $inRefPath)
{
// 在斜杠处分割字符串
$s_parts = explode('/', $inSourcePath);
$r_parts = explode('/', $inRefPath);
// 删除第一个不相同部分之前的项目
while ($s_parts[0] === $r_parts[0])
{
array_shift($s_parts);
array_shift($r_parts);
}
// 为 $s_parts 的每个剩余项目向 $r_parts 添加通配符
// 项目
while ($s_parts[0])
{
array_unshift($r_parts, '..');
array_shift($s_parts);
}
return implode('/', $r_parts);
}
//----------------------------------------------------------
// 示例:
// 给定源路径 $sp,生成 $rp 的相对位置。 $sp 可以使用
// $_SERVER['PHP_SELF'] 赋值,但在此示例中为硬编码。
//----------------------------------------------------------
$sp = '/WebServer/Documents/MyBigProject/php/project_script.php';
$rp = '/WebServer/Documents/MyLibraries/lib_script.php';
// 将它们插入函数中
$rel_path = create_relative_path($sp, $rp);
// 生成
'../../../MyLibraries/lib_script.php'
// 并可以像这样使用
include_once(create_relative_path($_SERVER['PHP_SELF'], $rp));
一个简单的基准测试(PHP 8.1.9 + macOS 12.4)
<?php
ini_set('memory_limit', -1);
$times = 25_000;
$length = 256;
$arr = [];
$random = random_bytes(($times + $length) / 2);
$random = bin2hex($random);
// 基准测试 array_shift()
for ($i = 0; $i < $times; $i++) {
$arr[$i] = substr($random, $i, $length);
}
$shiftTimer = -hrtime(true);
for ($i = 0; $i < $times; $i++) {
$value = array_shift($arr);
}
$shiftTimer += hrtime(true);
// 基准测试 array_reverse() + array_pop() + array_reverse()
for ($i = 0; $i < $times; $i++) {
$arr[$i] = substr($random, $i, $length);
}
$reverseTimer = -hrtime(true);
for ($i = 0; $i < $times; $i++) {
$arr = array_reverse($arr);
$value = array_pop($arr);
$arr = array_reverse($arr);
}
$reverseTimer += hrtime(true);
// 基准测试 array_reverse() + array_pop()
for ($i = 0; $i < $times; $i++) {
$arr[$i] = substr($random, $i, $length);
}
$popTimer = -hrtime(true);
$arr = array_reverse($arr);
for ($i = 0; $i < $times; $i++) {
$value = array_pop($arr);
}
$popTimer += hrtime(true);
// 基准测试 $arr[key()]+ unset(key())
for ($i = 0; $i < $times; $i++) {
$arr[$i] = substr($random, $i, $length);
}
$keyTimer = -hrtime(true);
reset($arr);
for ($i = 0; $i < $times; $i++) {
$key = key($arr);
$val = $arr[$key];
unset($arr[$key]);
}
$keyTimer += hrtime(true);
print_r([
'shift' => $shiftTimer / (10 ** 9),
'reverse' => $reverseTimer / (10 ** 9),
'pop' => $popTimer / (10 ** 9),
'key' => $keyTimer / (10 ** 9),
]);
?>
结果解读
在一个包含 25,000 个唯一项目的数组上,每个项目都是一个 256 字节的字符串
并且 key() + unset() 非常快。
array_shift() 慢约 400 倍
array_reverse() + array_pop() + array_reverse() 慢约 5,000 倍。
附注:我正在实现一个队列,因此我需要在 array_pop() 之后添加另一个 array_reverse(),这使得它在循环中变得极其缓慢。 array_reverse() + array_pop() 对我来说没有用,我只是为了检查它的性能而添加的。 它与 key() + unset() 一样快。
// 例 1:signedShiftArray (['A', 'B', 'C', 'D'], 2) -> ['C', 'D', 'A', 'B']
// 例 2:signedShiftArray (['A', 'B', 'C', 'D'], -3) -> ['B', 'C', 'D', 'A']
// 例 3:signedShiftArray (['A', 'B', 'C', 'D'], -7) -> ['B', 'C', 'D', 'A']
function signedShiftArray ($aItems, $aOffset)
{
if (empty ($aItems))
return [];
else if (empty ($aOffset))
return $aItems;
else {
$t= count ($aItems);
$n= $aOffset % $t;
$m= $aOffset > 0 ? $n : $t + $aOffset;
return array_merge(array_slice($aItems, $n), array_slice($aItems, 0, $m));
}
}
行内赋值不会删除元素。
$first = array_shift( $arr = array( 0 => '1st', 2 => '2nd', 3 => '3rd') );
print_r( $first );
print_r( $arr );
输出
1st
数组
(
[0] => 1st
[2] => 2nd
[3] => 3rd
)
// 通过 Saurabh Goyal 更改数组顺序
function change_array_order($table,$order)
{
// 初始化新表
$new_table = array();
foreach($order as $colname)
{
$new_table[$colname] = $table[$colname];
}
return $new_table;
}
如果数组值类似于:
$row = array('usr_id'=>'23','usr_name'=>'Saurabh', 'usr_surname'=>'Goyal','usr_firstname'=>'Saurabh');
// 您想更改顺序并仅显示特定字段
change_array_order($row,array('usr_name','usr_firstname',
'usr_surname'));
此致
Saurabh Goyal
http://sggoyal.blogspot.com
[email protected],我认为这种方法效率更高。
<?php
function array_shorten($arr)
{
list($k) = array_keys($arr);
unset($arr[$k]);
return $arr;
}
?>
我需要从关联数组中删除第一组键值对。不得不编写此函数
function shortenArray($_arr)
{
$i=1;
$_shorter=array();
foreach ($_arr as $k => $v)
{
if ($i != 1)
{
$_shorter[$k] = $v;
}
$i++;
}
return $_shorter;
}
如果您想遍历一个数组,使用 array_shift() 一次删除一个值,但也希望得到键,请尝试以下方法。
<?php
while($key = key($array))
{
$value = array_shift($array);
// 代码在此处
}
?>
它类似于 foreach,但每次都会从数组中删除值,因此最终数组会变为空。
<?php
// 下面的示例
$airports = array
(
"LGW" => "London Gatwick",
"LHR" => "London Heathrow",
"STN" => "London Stanstead"
);
echo count($airports)." Airport in the array<br /><br />";
while($key = key($airports))
{
$value = array_shift($airports);
echo $key." is ".$value."<br />";
}
echo "<br />".count($airports)." Airport left in the array";
?>
示例输出
数组中有 3 个机场
LGW 是伦敦盖特威克机场
LHR 是伦敦希思罗机场
STN 是伦敦斯坦斯特德机场
数组中剩余 0 个机场
我使用此函数来浏览数据库中的数组。例如数据
<?php
$data = array(
array('row 1-cell 1','row 1-cell 2'),
array('row 2-cell 1','row 2-cell 2'),
array('row 3-cell 1','row 3-cell 2'),
);
while($row=array_shift($data)) {
echo $row[0];
}
?>
输出
row 1-cell 1
row 2-cell 1
row 3-cell 1
while(array_shift()) 可用于在一个循环中处理多个数组和/或数据库结果。|| 会短路,并且只评估第一个语句,直到数据用完。
它有助于减少重复代码(规则是只写一次代码)。
请注意,每个 ($row = ) 语句都必须用 () 括起来,否则您将得到奇怪的结果。如果您使用两个 array_shift($array) 语句并忘记了 (),您将反复获得第一个数组的第一个元素,次数为 $array 的计数。
<?php
require_once('class.db.php');
$sql = "SELECT title FROM links";
$result = mysql_query($sql, $db->connection);
$defaults = array(
array('title' => 'None'),
array('title' => 'Unknown')
);
while ( ($row = mysql_fetch_assoc($result))
|| ($row = array_shift($defaults)))
{
echo $row['title'] . "<br>";
}
?>
这将打印输出(取决于数据库内容)
Title1
Title2
Title3
...
None
Unknown
我还没有深入研究,但如果您抱怨 PHP 5.0.5 中的更改导致您无法执行以下操作
<?php
$val = array_shift(preg_split());
?>
或
<?php
$val = array_shit(function_that_returns_array);
?>
那么您使用此函数的方式不正确。此函数的参数应该是指向变量的指针。然后它修改该变量并返回值。当您指定一个函数时,php 无法修改该函数的返回值。这应该是常识,但显然不是。
此外,在效率方面,您可能需要考虑使用其他函数,例如 reset,或者可能创建您自己的函数,如下所示
<?php
function first_element($array) {
return reset($array);
}
?>
除非出于某种原因,您需要保存这需要花费的微秒数。
}
如果您需要数组的第一个或最后一个条目,那么这可以帮助您。
<?php
function array_last_entry($arr){
if(!is_array($arr))
return;
if(empty($arr))
return;
return end($arr);
}
function array_first_entry($arr){
if(!is_array($arr))
return;
if(empty($arr))
return;
reset($arr);
return current($arr);
}
$arr = array( '5' => 'five', '3' => 'three', '8' => 'eight',);
echo 'last entry: '.array_last_entry($arr).'<br>';
echo 'first entry: '.array_first_entry($arr).'<br>';
echo 'alternative output:<br>';
echo 'last entry: '.$arr[count($arr)-1];
echo '<br>first entry: '.$arr[0];
?>
输出将如下所示
最后一个条目:eight
第一个条目:five
备选输出
最后一个条目
第一个条目
如您所见,如果您需要处理索引不连续的数组,这些函数可能非常有用。
如果数组具有非数值键,array_shift 将提取第一个元素(无论键是什么),并重新计算数值键(如果有)。例如:
$array = array("c" => "ccc", 0 => "aaa", "d" => "ddd", 5 => "bbb");
$first = array_shift($array);
echo '$first = ' . $first . ', $array = ' . var_export($array, true);
将显示
$first = ccc, $array = array ( 0 => 'aaa', 'd' => 'ddd', 1 => 'bbb', )
这意味着 array_shift 也适用于关联数组,并且如果键是非数值的,则保持键不变。
如果您想要一个非破坏性工作的 array_shift() 版本(即,一个易于使用的函数,用于获取数组的第一个元素而不修改数组),请尝试使用 reset()。