在較大的陣列上使用 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
一個元素,並將所有元素向下移動。所有數值鍵都會被修改,從零重新開始計數,而字串鍵則不會受到影響。
注意:此函式在使用後會將輸入陣列的陣列指標 reset()。
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
/**
* This function exhibits the same behaviour is array_shift(), except
* it returns a reference to the first element of the array instead of a copy.
*
* @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: The array should be shifted one element left');
}
function testFunctionRemovesFirstElementOfAssociativeArray()
{
$input = array('x' => 'foo', 'y' => 'bar');
array_shift_reference($input);
$this->assertEqual(array('y' => 'bar'), $input, '%s: The array should be shifted one element left');
}
function testFunctionReturnsReferenceToFirstElementOfNumericallyIndexedArray()
{
$foo = 'foo';
$input = array(&$foo, 'bar');
$first =& array_shift_reference($input);
$this->assertReference($foo, $first, '%s: The return value should reference the first array element');
}
function testFunctionReturnsReferenceToFirstElementOfAssociativeArray()
{
$foo = 'foo';
$input = array('x' => &$foo, 'y' => 'bar');
$first =& array_shift_reference($input);
$this->assertReference($foo, $first, '%s: The return value should reference the first array element');
}
function testFunctionReturnsNullIfEmptyArrayPassedAsInput()
{
$input = array();
$first = array_shift_reference($input);
$this->assertNull($first, '%s: Array has no first element so NULL should be returned');
}
}
?>
要從陣列的**中間**移除一個元素(類似於 `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 class
*
* @package Framework
*/
/**
* Command Line Interface (CLI) utility class.
*
* @author Patrick Fisher <patrick@pwfisher.com>
* @since August 21, 2009
* @package Framework
* @subpackage Env
*/
class CommandLine {
/**
* PARSE ARGUMENTS
*
* [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 <patrick@pwfisher.com>
* @since August 21, 2009
* @see https://php.dev.org.tw/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);
// benchmark 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);
// benchmark 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);
// benchmark 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);
// benchmark $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" => "London Gatwick",
"LHR" => "London Heathrow",
"STN" => "London Stanstead"
);
echo count($airports)." 個機場在陣列中<br /><br />";
while($key = key($airports))
{
$value = array_shift($airports);
echo $key." 是 ".$value."<br />";
}
echo "<br />".count($airports)." 個機場留在陣列中";
?>
範例輸出
3 個機場在陣列中
LGW 是 London Gatwick
LHR 是 London Heathrow
STN 是 London Stanstead
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_shift(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 '替代輸出:<br>';
echo 'last entry: '.$arr[count($arr)-1];
echo '<br>first entry: '.$arr[0];
?>
輸出結果如下:
last entry: eight
first entry: five
替代輸出
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 也適用於關聯式陣列 (associative arrays),並且如果鍵值是非數值的,則會保持鍵值不變。
如果您需要 array_shift() 的非破壞性版本(例如,一個簡單的函式來取得陣列的第一個元素而不修改陣列),請嘗試使用 reset()。