iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 6
0
自我挑戰組

花式PHP系列 第 6

Array:操作、查詢

  • 分享至 

  • xImage
  •  

今天要講什麼呢?先講結論:

  1. 移除並回傳陣列的第一個 element
  2. 在陣列最前面新增一個 element
  3. 在陣列前面塞一些 elements 直到指定的長度
  4. 搜尋一個值存不存在於 values 之中

array_shift & array_unshift

注意!這兩個函式都會直接對傳入的陣列修改!

一般在陣列最後面新增 element 我們都是用 array_push()$array[] = 'value'; 做的。

但如果我們打算在陣列最前面新增 element 呢?
我們什麼時候可能會需要這麼做?

想像一下,現在你正在日本的一間肯德基排隊。
因為今天是聖誕節,所以人特別的多,此時有位不速之客自顧自的插隊進來了...

<?php

class Server
{
    public static function removeFirst(&$line)
    {
        return array_shift($line);
    }
}

class UnmanneredCustomerRemover extends Server
{
    //
}

class Customer
{
    public $id;
    
    public function __construct($id)
    {
        $this->id = "普通顧客-{$id}";
    }
    
    public function getInLine(&$line)
    {
        array_push($line, $this);
        // $line[] = $this;
    }
}

class UnmanneredCustomer extends Customer
{
    public function __construct($id)
    {
        $this->id = "沒禮貌的客人-{$id}";
    }
    
    public function getInLine(&$line)
    {
        array_unshift($line, $this);
    }
}

// 隊伍
$line  = [];

// 顧客進場
foreach (range(1, 10) as $id) {
    $customer = new Customer($id);
    $customer->getInLine($line);
}

// 你進場
$customer = new Customer('媽我在這');
$customer->getInLine($line);

// 沒禮貌的客人進場
$unmanneredCustomer = new UnmanneredCustomer(11);
$unmanneredCustomer->getInLine($line);

// 店家的反應
foreach ($line as $customer) {
    if ($customer instanceof UnmanneredCustomer) {
        UnmanneredCustomerRemover::removeFirst($line);
        echo "Kicked: {$customer->id}" . PHP_EOL;
    } else {
        Server::removeFirst($line);
        echo "Served: {$customer->id}" . PHP_EOL;
    }
}

看完範例之後

不曉得大家有沒有注意到,代表排隊隊伍的 $line 其實就是一個 queue 呢?

因為是要做成先進先出 (FIFO) 的 queue,
所以正常顧客都是透過 array_push 把自己放在隊伍最後面,
店家則是一直要透過 array_shift 得到隊伍中排在最前面的客人。
沒禮貌的客人卻是用 array_unshift 把自己排進隊伍的第一位的~

大家應該看得懂這個範例吧~
/images/emoticon/emoticon42.gif

array_pad

注意!這個函式不會直接對傳入的陣列修改,它會把填充過的陣列回傳

array_pad,顧名思義就是 Pad array with values,
這個 function 可以幫你把陣列填充到指定的長度。

比較值得一提的是它的第二個參數,大家可以搭配底下的範例看:
第二個參數告訴 array_pad 應該要填充 array 到有多長之後停止。

自然的,當你給定的數字比 array 本身的長度還大的時候,它什麼都不會做。
但要如何理解一個負整數對 array_pad 的行為有什麼影響呢?

是這樣的,
array_pad 會從給定的數字中解讀出兩件事情:

  1. 數字的正負號:往哪個方向填充(負左正右)
  2. 數字的絕對值:應該要填充到多長為止

重點就這樣,搭配這兩條規則應該能充分解釋底下輸出的結果了~
/images/emoticon/emoticon08.gif

<?php

// 隊伍
$line  = [];

// 你進場
$line[] = '你';

// 阿飄出現了
print_r(array_pad($line, 3, 'Ghost'));
print_r(array_pad($line, -3, 'Ghost'));

// output:
// Array
// (
//     [0] => 你
//     [1] => Ghost
//     [2] => Ghost
// )
// Array
// (
//     [0] => Ghost
//     [1] => Ghost
//     [2] => 你
// )

延伸閱讀:
如果你想要在陣列中的某一點開始填充,看看 array_fill

array_search

這個 function 會用來尋找陣列中有沒有指定的值,
有的話則回傳他的 index;
沒有的話則回傳 FALSE;

注意!因為回傳的 index 可能是 0,在模糊比較的時候 0 與 false 是一樣的!
在對回傳的值做判斷時請特別注意這點!

參數:

  1. 要搜尋的值
  2. 要被搜尋的陣列
  3. 是否要進行嚴格比較(通常是 false)

範例

/images/emoticon/emoticon11.gif

大家以前在國高中小上課的時候應該都有睡著的經驗吧?
但大家有被目光銳利的老師用粉筆丟過嗎?

底下的範例使用一個有 5x5 的座位表,
每一行的座位裡會有隨機一位同學_(也有可能沒有)_睡著了。

老師會對每一行不斷地使用 array_search 找出睡著(student == 'slept')的同學,並對他丟粉筆,
直到那一行沒有睡著的同學為止!

<?php

function getSeats($limit)
{
    /**
     * 得到一個在指定範圍內的數字
     * @see http://php.net/manual/en/function.rand.php
     */
    $awakeStudnetCounts = rand($limit - 1, $limit);
    
    /**
     * @see http://php.net/manual/en/function.array-fill.php
     */
    $students = array_fill(0, $awakeStudnetCounts, 'awake');
    
    return array_pad($students, $limit, 'slept');
}

// 教室座位
$lines = [
    getSeats(5),
    getSeats(5),
    getSeats(5),
    getSeats(5),
    getSeats(5),
];

// 老師要丟粉筆啦!!!
/**
 * 
 */
foreach ($lines as $lineIndex => &$line) {
    while ($rowIndex = array_search('slept', $line)) {
        $line[$rowIndex] = 'awake';
        echo "Student {$lineIndex}-{$rowIndex} was hit by teacher's chalk!" . PHP_EOL;
    }
}

上一篇
Array:排序
下一篇
Array:取得資料
系列文
花式PHP31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言