PHP 多維數組中的 array_find

過渡

最近在開始使用 ThinkPHP 5.1 進行一系列開發工做,由於以前是使用 Laravel 進行開發,像是標題中的這種小問題都在 Laravel 中很容易實現。直接使用 array_first 方法進行查找便可。php

快速實現

可是在 ThinkPHP 中 並無提供相似方法進行快速處理,因此有須要來重複造輪子了?
至此想到的第一個方法就是使用 array_search 不過這個方法中官方提供的方案僅用於簡單的一維數組搜索,並且返回的也只是 index 並非找到的結果,淡然經過 index 咱們也能夠取出項目來,在 PHP 5.5 帶來的新方法 array_column,能夠方便的實現二維搜索 在這裏的用戶筆記 爲咱們提供了一個小的示例。laravel

$userdb=Array
(
    (0) => Array
        (
            (uid) => '100',
            (name) => 'Sandra Shush',
            (url) => 'urlof100'
        ),

    (1) => Array
        (
            (uid) => '5465',
            (name) => 'Stefanie Mcmohn',
            (pic_square) => 'urlof100'
        ),

    (2) => Array
        (
            (uid) => '40489',
            (name) => 'Michael',
            (pic_square) => 'urlof40489'
        )
);

$key = array_search(40489, array_column($userdb, 'uid'));

而且贏得了 800+ 的讚揚,到這裏可能你會以爲 經過這個方式取到 index 而後用 index 取出來就好了。git

一些🌰

可是,若是你再往下翻一下,你會看到另外一條用戶筆記 ,這條用戶筆記告訴咱們 當咱們使用這種方式來實現二維搜索時你 PHP 版本 必需要在 5.5 + ,做者同時告訴咱們github

Since array_column() will produce a resulting array; it won't preserve your multi-dimentional array's keys. So if you check against your keys, it will fail.
機翻一下 :因爲array_column()將產生一個新的數組; 它不會保留多維數組的原來的鍵。 所以,若是您檢查您的鍵,它將失敗。

而後做者也爲咱們提供了一個🌰數組

$people = array(
  2 => array(
    'name' => 'John',
    'fav_color' => 'green'
  ),
  5 => array(
    'name' => 'Samuel',
    'fav_color' => 'blue'
  )
);

$found_key = array_search('blue', array_column($people, 'fav_color')); // 1

// Here, you could expect that the $found_key would be "5" but it's NOT. It will be 1. Since it's the second element of the produced array by the array_column() function.
// 機翻一下:在這裏,你預期 $found_key 的將是「5」,但它不是,它將是1.由於它是array_column()函數生成的數組的第二個元素。

// 另外 做者還提到了
// Secondly, if your array is big, I would recommend you to first assign a new variable so that it wouldn't call array_column() for each element it searches. For a better performance, you could do;
// 機翻一下:其次,若是您的數組很大,我建議您先分配一個新變量,這樣它就不會爲它搜索的每一個元素調用array_column()。 爲了得到更好的性能,你能夠作到;

$colors = array_column($people, 'fav_color');
$found_key = array_search('blue', $colors);

看完了這些提示,你已經發現了這其中的坑,然而,這並無結束,由於若是數據不夠純淨的話,你用 array_search 實現的功能可能就只侷限於 in_array
並且,儘管到了這裏,還會遇到另一個坑,先看🌰函數

<?php 
$userdb = array(
    0 => array(
            'uid' => 100,
            'name' => 'Sandra Shush',
            'url' => 'urlof100'
        ),
 
    '8' => array(
            'uid' => 5465,
            'name' => 'Stefanie Mcmohn',
            'pic_square' => 'urlof100'
        ),
 
    '3' => Array(
            // 'uid' => 5555,
            'name' => 'Michael',
            'pic_square' => 'urlof40489'
        ),
 
    '6' => Array(
            'uid' => 40489,
            'name' => 'Michael',
            'pic_square' => 'urlof40489'
        )
);
 
$found_key = array_search(40489, array_column($userdb, 'uid'));

在這裏 猜測一下 $found_key 會是什麼?答案是: 2
??? ,由於當在執行 array_column() 時,第三個元素,也就是鍵爲3的數據中 uid 被註釋了,這時候 PHP 就會忽略它,並不會被保留索引位置,因此這時候結果只有 3 個元素,第四個向上替補了,由於數組索引是 0 開始,因此 2 就至關於第 3 個元素了。性能

你們都是怎麼作的?

array_search 的用戶筆記區中,看到了不少都是數組循環並比對後返回,好比這個,可是這樣又遇到一些侷限性問題,這時候咱們又想到了 Laravel 中把自主權交給調用者,由調用者在匿名方法內進行處理並返回 bool 值 進行處理。ui

至此,看回 Laravel 的 array_fisrt 方法,經過 Laravel 源碼能夠看到 array_first 是 Arr::fisrt 方法的一個包裝,在這裏咱們能夠看到 Laravel 的實現方式,在這一小段代碼中 還看到了另外一個方法 value(),能夠看到,這個方法就是判斷是不是一個匿名方法,若是是就執行方法並返回,不是就直接返回。url

public static function first($array, callable $callback = null, $default = null)
    {
        if (is_null($callback)) {
            if (empty($array)) {
                return value($default);
            }
            foreach ($array as $item) {
                return $item;
            }
        }
        foreach ($array as $key => $value) {
            if (call_user_func($callback, $value, $key)) {
                return $value;
            }
        }
        return value($default);
    }
if (! function_exists('value')) {
    /**
     * Return the default value of the given value.
     *
     * @param  mixed  $value
     * @return mixed
     */
    function value($value)
    {
        return $value instanceof Closure ? $value() : $value;
    }
}

看到這裏,幾乎是比較完整的實現,在這裏還想到了另一個和助手函數有關的項目:Underscore.php
這是一個 PHP 的方法庫,也能夠算是是 JS中的 underscore.jsloadshramda 的 PHP 實現。
在這個項目中咱們看到了實現方式.net

public static function find($array, Closure $closure)
    {
        foreach ($array as $key => $value) {
            if ($closure($value, $key)) {
                return $value;
            }
        }
        return;
    }

這裏的實現更爲簡單,最終也實現了咱們想要的結果。

相關文章
相關標籤/搜索