在较大数组上使用 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] => Array
(
[0] => Country
[1] => CountryCode
[2] => City
[3] => CityOtherLanguage
[4] => PostCode
[5] => Days
)
[1] => Array
(
[0] => Turkey
[1] => TR
[2] => Istanbul
[3] => Istanbul
[4] => 34930
[5] => 9
)
)
$cargo_file = array_shift($cargo_file);
echo "<pre>";
print_r($cargo_file);
echo "</pre>";
// 结果之后
/*
数组
(
[0] => Country
[1] => CountryCode
[2] => City
[3] => CityOtherLanguage
[4] => PostCode
[5] => Days
)
*/
我开发了一个解决方案
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] => Array
(
[0] => Turkey
[1] => TR
[2] => Istanbul
[3] => Istanbul
[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));
}
}
有时你不需要打乱数组,只需要旋转它。 我们可以用以下代码轻松地将数组向左旋转
<?php
$arr[] = array_shift($arr);
?>
行内的赋值不会删除元素。
$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
baughmankr at appstate dot edu,我认为这样更有效率。
<?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" => "伦敦盖特威克",
"LHR" => "伦敦希思罗",
"STN" => "伦敦斯坦斯特德"
);
echo count($airports)." 个机场在数组中<br /><br />";
while($key = key($airports))
{
$value = array_shift($airports);
echo $key." 是 ".$value."<br />";
}
echo "<br />".count($airports)." 个机场剩余在数组中";
?>
示例输出
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];
?>
输出将如下所示
last entry: eight
first entry: five
alternative output
last entry
first entry
如你所见,如果你必须处理具有非连续索引的数组,这些函数可能非常有用。
如果数组具有非数值键,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 也适用于关联数组,如果键是非数值的,则保持键不变。
这在二维数组中不起作用。对于二维数组,我这样做
<?php
$backup = $arr;
$first = array_shift ( $backup );
?>
如果你想要一个非破坏性的 array_shift() 版本(即,一个简单的函数来获取数组的第一个元素,而不会修改数组),请尝试使用 reset()。