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;
    }

这里的实现更为简单,最终也实现了咱们想要的结果。

相关文章
相关标签/搜索