PHP实现自己的ArrayUtil

<?php
require_once 'lambda.php';

class ArrayUtils
{
    private $array;

    public function __construct($array)
    {
        $this->array = $array;
    }

    public static function similar($arr1, $arr2, $function = null)
    {
        if (count($arr1) != count($arr2))
        {
            return false;
        }

        foreach ($arr1 as $ka => $a)
        {
            $findSame = false;
            foreach ($arr2 as $kb => $b)
            {
                if ($function == null ? $a == $b : call_user_func($function, $a, $b))
                {
                    $findSame = true;
                    unset($arr2[$kb]);
                    break;
                }
            }
            if (!$findSame)
            {
                return false;
            }
        }
        return true;
    }

    public function removeIf($function) {
        for ($index = 0; $index < count($this->array); ) {
            if ($function($this->array[$index])) {
                array_splice($this->array, $index, 1);
            }
            else {
                $index++;
            }
        }
        return $this;
    }

    public function where($function, $keepKey = false) {
        $result = [];
        foreach ($this->array as $key => $item) {
            if ($function($item)) {
                if ($keepKey) {
                    $result[$key] = $item;
                }
                else
                {
                    $result[] = $item;
                }
            }
        }
        $this->array = $result;
        return $this;
    }

    public function findKey($function) {
        foreach ($this->array as $key => $item) {
            if ($function($item)) {
                return $key;
            }
        }
        return false;
    }

    public function findLastKey($function) {
        $index = false;
        foreach ($this->array as $key => $item) {
            if ($function($item)) {
                $index = $key;
            }
        }
        return $index;
    }

    public function findValue($function)
    {
        foreach ($this->array as $key => $item) {
            if ($function($key)) {
                return $item;
            }
        }
        return false;
    }

    public function select($function) {
        $result = [];
        foreach ($this->array as $key => $item) {
            $result[] = $function($item, $key);
        }
        $this->array = $result;
        return $this;
    }

    public function distinct($function = null) {
        $result = [];
        foreach ($this->array as $key => $item) {
            $distinct = true;
            foreach ($result as $re) {
                if ($function == null ? $item == $re : call_user_func($function, $item, $re)) {
                    $distinct = false;
                }
            }
            if ($distinct) {
                $result[] = $item;
            }
        }
        $this->array = $result;
        return $this;
    }

    public function groupBy($function) {
        $result = [];
        foreach ($this->array as $key => $item) {
            $groupKey = $function($item, $key);

            $group = null;
            foreach ($result as &$value) {
                if ($value['groupKey'] == $groupKey) {
                    $group = &$value;
                    break;
                }
            }

            if ($group === null) {
                $group = [
                    'groupKey' => $groupKey,
                    'groupItems' => []
                ];
                $result[] = &$group;
            }

            $group['groupItems'][] = $item;
            unset($group);
        }

        $this->array = $result;
        return $this;
    }

    // $options = ['store', 'models' => 'model', 'images' => 'image']
    public function groupToTree($options) {
        $value = $options[0];
        $keys = array_keys($options);
        $children = $keys[1];
        $next_options[] = $options[$children];
        $next_options = array_merge($next_options, array_splice($options, 2));

        $this->groupBy(function ($item) use ($value) {
            return $item[$value];
        });

        $this->select(function ($item) use ($children, $value, $next_options) {
            $result = $item['groupKey'];
            $group = ArrayUtils($item['groupItems'])->where(function ($item) {
                foreach ($item as $field) {
                    if ($field !== null) {
                        return true;
                    }
                }
                return false;
            })->select(function ($child) use ($value, $next_options) {
                unset($child[$value]);
                return $child;
            });
            if (count($next_options) > 1) {
                $result[$children] = $group->groupToTree($next_options)->all();
            }
            else {
                $result[$children] = $group->select(function ($child) use ($next_options) {
                    return $child[$next_options[0]];
                })->all();
            }
            return $result;
        });

        return $this;
    }

    public function orderBy($function = null) {
        $len = count($this->array);
        for ($i = 1; $i < $len; $i++) {
            $flag = false;
            for ($k = 0; $k < $len - $i; $k++) {
                if ($function == null ? $this->array[$k] > $this->array[$k + 1] : call_user_func($function, $this->array[$k]) > call_user_func($function, $this->array[$k + 1])) {
                    $tmp = $this->array[$k + 1];
                    $this->array[$k + 1] = $this->array[$k];
                    $this->array[$k] = $tmp;
                    $flag = true;
                }
            }
            if (!$flag) break;
        }
        return $this;
    }

    public function orderByCompare($function = null) {
        $len = count($this->array);
        for ($i = 1; $i < $len; $i++) {
            $flag = false;
            for ($k = 0; $k < $len - $i; $k++) {
                if ($function == null ? $this->array[$k] > $this->array[$k + 1] : call_user_func($function, $this->array[$k], $this->array[$k + 1])) {
                    $tmp = $this->array[$k + 1];
                    $this->array[$k + 1] = $this->array[$k];
                    $this->array[$k] = $tmp;
                    $flag = true;
                }
            }
            if (!$flag) break;
        }
        return $this;
    }

    public function orderByDesc($function = null) {
        $len = count($this->array);
        for ($i = 1; $i < $len; $i++) {
            $flag = false;
            for ($k = 0; $k < $len - $i; $k++) {
                if ($function == null ? $this->array[$k] < $this->array[$k + 1] : call_user_func($function, $this->array[$k]) < call_user_func($function, $this->array[$k + 1])) {
                    $tmp = $this->array[$k + 1];
                    $this->array[$k + 1] = $this->array[$k];
                    $this->array[$k] = $tmp;
                    $flag = true;
                }
            }
            if (!$flag) break;
        }
        return $this;
    }


    public function sum($function) {
        $result = 0;
        foreach ($this->array as $item) {
            $result += $function($item);
        }
        return $result;
    }

    public function max($function = null, $lessThan = null) {
        $maxValue = null;
        $maxItem = null;
        foreach ($this->array as $key => $item) {
            $value = $function == null ? $item : call_user_func($function, $item, $key);
            if ($maxItem === null) {
                $maxItem = $item;
                $maxValue = $value;
            }
            else if ($lessThan == null ? $maxValue < $value : call_user_func($lessThan, $maxItem, $item)) {
                $maxItem = $item;
                $maxValue = $value;
            }
        }
        return $maxValue;
    }

    public function maxItem($function) {
        return $this->max(null, function ($l, $r) use ($function) {
            return $function($l) < $function($r);
        });
    }

    public function min($function = null, $lessThan = null) {
        $minValue = null;
        $minItem = null;
        foreach ($this->array as $key => $item) {
            $value = $function == null ? $item : call_user_func($function, $item, $key);
            if ($minItem === null) {
                $minItem = $item;
                $minValue = $value;
            }
            else if ($lessThan == null ? $minValue > $value : !call_user_func($lessThan, $minItem, $item)) {
                $minItem = $item;
                $minValue = $value;
            }
        }
        return $minValue;
    }

    public function all() {
        return $this->array;
    }

    public function first() {
        return $this->array[0];
    }

    public function firstOrNull() {
        if (count($this->array) > 0) {
            return $this->first();
        }
        return null;
    }

    public function limit($start, $length, $keepKey = false) {
        $start = ($start - 1) < 0 ? 0 : ($start - 1) * $length;
        $this->array = array_slice($this->array, $start, $length, $keepKey);
        return $this;
    }
}

function ArrayUtils($array) {
    return new ArrayUtils($array);
}
1. 静态方法 similar(),用于比较两个数组是否相似。以下是该方法的功能:
检查数组长度:首先,该方法会检查传入的两个数组 $arr1 和 $arr2 的长度是否相等,如果不相等,则直接返回 false。
逐一比较元素:
接着,方法会在循环中遍历第一个数组 $arr1 中的每个元素。
对于每个元素 $a,在内部循环中遍历第二个数组 $arr2 中的元素 $b。
如果没有指定自定义比较函数 $function(默认为 null),则使用简单相等性判断($a == $b)来比较元素;否则,调用指定的自定义比较函数来进行比较。
如果找到了相同的元素,将其从第二个数组中移除,并继续处理下一个元素。
如果无法找到相同的元素,则立即返回 false,表示两个数组不相似。
返回结果:如果成功比较完所有元素且两个数组中的元素都具有相匹配的对应项,则最终返回 true,表示这两个数组是相似的。
2. where 方法,用于按照给定的条件筛选数组中的元素,并根据参数 $keepKey 决定是否保留键名。以下是该方法的功能:
接受条件函数:where 方法接受两个参数,第一个参数是条件函数 $function,用于判断数组中的每个元素是否符合特定条件。
根据条件筛选元素:
在方法中遍历原始数组 $this->array 中的每个元素。
对于每个元素,将其作为参数传递给条件函数 $function 进行评估。
如果条件函数返回 true,表示该元素符合条件,则根据 $keepKey 参数的设置决定是否保留键名。
如果 $keepKey 为 true,则将符合条件的元素及其对应键名存储到结果数组 $result 中。
如果 $keepKey 为 false,则只将符合条件的元素存储到结果数组 $result 中。
最终得到筛选后的结果数组 $result。
更新原始数组和返回对象:
将筛选后的结果数组赋值给原始数组 $this->array,即覆盖原始数组中的元素。
返回当前对象本身,以支持链式调用。
通过这个方法,您可以根据自定义条件函数对数组进行筛选,并选择是否保留键名。这种方法通常在需要根据特定条件过滤数组元素时使用。
3. findKey 方法,该方法用于在数组中查找符合特定条件的元素,并返回第一个满足条件的元素的键名。以下是该方法的功能:

接受条件函数:

findKey 方法接受一个条件函数 $function,该函数用于评估数组中的每个元素。
遍历原始数组:

在方法中循环遍历原始数组 $this->array 中的每个元素,同时获取键名和值。
查找满足条件的第一个元素:

对于每个元素,将其传递给条件函数 $function 进行评估。
如果条件函数返回 true,表示找到了符合条件的元素,则立即返回该元素的键名。
返回结果:

如果找不到任何满足条件的元素,最终返回 false,表示未找到符合条件的元素,或者数组为空。
通过这个方法,您可以方便地在数组中查找符合指定条件的元素,并返回第一个满足条件的元素的键名。这种方法通常在需要快速定位数组中满足特定条件的元素时使用。
4. findLastKey 方法,用于在数组中查找符合特定条件的元素,并返回最后一个满足条件的元素的键名。以下是该方法的功能:

初始化变量:

在方法开始时,初始化一个变量 $index 为 false,用于存储满足条件的最后一个元素的键名。
遍历原始数组:

在方法中循环遍历原始数组 $this->array 中的每个元素,同时获取键名和值。
查找满足条件的最后一个元素:

对于每个元素,将其传递给条件函数 $function 进行评估。
如果条件函数返回 true,表示找到了符合条件的元素,则更新 $index 变量为当前元素的键名。
返回结果:

完成整个数组遍历后,返回存储的最后一个满足条件的元素的键名,如果没有找到满足条件的元素,则返回初始值 false。
通过这个方法,您可以在数组中查找符合指定条件的元素,并返回最后一个满足条件的元素的键名。这种方法通常在需要找到数组中最后一个满足特定条件的元素时使用。
5. findValue 方法,用于在数组中查找满足特定条件的元素,并返回其对应的值。以下是该方法的功能:

接受条件函数:

findValue 方法接受一个条件函数 $function,该函数用于评估数组中的每个键名。
遍历原始数组:

在方法中循环遍历原始数组 $this->array 中的每个元素,获取键名和对应的值。
查找满足条件的元素:

对于每个元素,将其键名传递给条件函数 $function 进行评估。
如果条件函数返回 true,表示找到了符合条件的键,则返回对应的值。
返回结果:

如果未找到满足条件的键名,最终返回 false,表示未找到符合条件的元素或数组为空。
通过这个方法,您可以根据条件函数在数组中查找满足特定条件的元素,并返回对应的值。这种方法通常在需要根据键名来查找相应值的情况下使用。
6. select 方法,该方法用于对数组中的每个元素应用指定函数,并将函数的返回值存储到新的数组中。以下是该方法的功能:

创建结果数组:

在方法开始时,初始化一个空数组 $result,用于存储经过函数处理后的结果。
遍历原始数组:

使用循环遍历原始数组 $this->array 中的每个元素,同时获取键名和值。
对每个元素应用函数:

对于每个元素,调用参数中传入的函数 $function($item, $key),将当前元素的值和键名作为参数传递给这个函数。
将函数的返回值(即处理后的结果)添加到结果数组 $result 中。
更新数组和返回对象:

将处理后的结果数组 $result 赋值给原始数组 $this->array,以替换原始数组中的元素。
返回当前对象本身,以支持链式调用。
通过这个方法,您可以方便地对数组中的每个元素应用特定的函数,并将处理后的结果存储在新数组中。这种方法通常在需要对数组中的元素进行转换、映射或其他操作时使用。
7. distinct 方法,用于从数组中筛选出不重复的元素。以下是该方法的功能:

创建结果数组:

在方法开始时,初始化一个空数组 $result,用于存储不重复的元素。
遍历原始数组:

使用循环遍历原始数组 $this->array 中的每个元素,同时获取键名和值。
筛选不重复元素:

对于每个元素,通过内部的嵌套循环检查是否已经存在在 $result 中。
如果元素与任何已知元素相同,则将 distinct 标志设置为 false。
如果元素是独一无二的,则将其添加到 $result 中。
更新数组和返回对象:

将筛选后的结果数组 $result 覆盖原始数组 $this->array,从而获得不重复的元素列表。
返回当前对象本身,以支持链式调用。
通过这个方法,您可以方便地从数组中过滤出不重复的元素。该方法允许您提供一个可选的比较函数 $function,用于自定义比较逻辑。如果未提供比较函数,默认使用相等性运算符(==)来判断元素是否相同。这种方法通常在需要消除数组中的重复元素时使用。
8. groupBy 方法,用于根据指定的函数对数组中的元素进行分组。以下是该方法的功能:

创建结果数组:

在方法开始时,初始化一个空数组 $result,用于存储分组后的结果。
遍历原始数组并分组:

使用循环遍历原始数组 $this->array 中的每个元素,同时获取键名和值。
对每个元素应用传入的函数 $function($item, $key) 来计算该元素的分组键 groupKey。
分组逻辑:

在内部循环中,检查是否已经存在具有相同 groupKey 的分组。
如果找到匹配的分组,则将当前元素添加到该分组的 groupItems 中。
如果没有找到匹配的分组,则创建一个新分组,并将其加入到结果数组 $result 中。
更新数组和返回对象:

将处理后的结果数组 $result 覆盖原始数组 $this->array,从而实现根据指定函数进行分组后的数组。
返回当前对象本身,以支持链式调用。
通过这个方法,您可以根据特定条件对数组中的元素进行分组。每个分组包含一个 groupKey 作为标识和一个 groupItems 数组,其中存储符合该分组条件的元素。这种方法通常在需要按照特定规则对数组元素进行分类和分组时使用。
9.groupToTree 方法,用于将数组按照指定的方式转换为树形结构。以下是该方法的功能:

解析选项参数:

从提供的选项数组中提取所需的值和键名。
计算下一个要处理的选项并存储在 $next_options 中。
使用 groupBy 进行分组:

根据提供的值对数组进行分组操作。
使用 select 转换成树形结构:

对每个分组应用特定逻辑以构建树形结构。
内部使用 ArrayUtils 类对分组元素进行操作,并根据条件进行选择和转换。
递归构建树形结构:

如果还有更多的选项需要处理,则递归调用 groupToTree 方法来处理下一级分组。
在最后一层,通过 select 方法将最终结果转换为树形结构。
返回对象:

将处理后的树形结构数据存储在原始数组中,并返回当前对象本身,支持链式调用。
通过这个方法,您可以根据提供的选项将数组转换为树形结构。该方法使用递归和多次处理来构建树形数据,便于以树形方式展现数据或处理多层级关系的信息。
10.orderBy 方法,用于对数组中的元素进行排序。以下是该方法的功能:

进行冒泡排序:

该方法采用冒泡排序算法对数组中的元素进行排序。
冒泡排序是一种简单直观的排序算法,在每一轮遍历中比较相邻的元素,并根据条件交换它们的位置,将最大(或最小)的元素推向列表的末尾。
接受比较函数参数:

可选地接受一个比较函数 $function,用于自定义排序规则。
如果未提供比较函数,则默认使用大于号(>)进行比较。
排序逻辑:

外层循环控制每一轮的比较次数,内层循环进行相邻元素的比较和交换。
根据比较结果决定是否交换两个元素的位置,直到数组中的所有元素按照指定规则排序完毕。
返回对象:

将排序后的数组存储回原始数组 $this->array 中,并返回当前对象本身,以支持链式调用。
通过这个方法,您可以对数组中的元素进行排序操作。该方法使用冒泡排序算法,允许您传入自定义的比较函数来实现不同的排序需求。排序后的结果将存储在原始数组中并返回给调用者
11.orderByCompare 方法,与之前提到的 orderBy 方法相似,也是用于对数组中的元素进行排序。以下是该方法的功能:

冒泡排序的改进:

与 orderBy 方法类似,orderByCompare 方法也使用冒泡排序算法来对数组中的元素进行排序。
不同之处在于,orderByCompare 方法允许传入比较函数 $function 来执行自定义的比较操作。
接受比较函数参数:

可选参数 $function 表示比较函数,用于决定数组中两个元素的顺序。
在每次比较相邻的元素时,根据比较函数的返回值(true 或 false)来决定是否交换它们的位置。
排序逻辑:

外层循环控制每一轮的比较次数,内层循环进行相邻元素的比较和交换。
根据比较函数的返回值决定是否交换两个元素的位置,直到数组中的所有元素按照指定规则排序完毕。
返回对象:

将排序后的数组存储回原始数组 $this->array 中,并返回当前对象本身,以支持链式调用。
通过这个方法,您可以通过自定义的比较函数来对数组中的元素进行排序操作。排序结果将根据给定的比较函数决定元素的顺序,最终得到按照指定规则排序的数组。
12. orderByDesc 方法,用于对数组中的元素进行降序排序。以下是该方法的功能:

降序排序逻辑:

类似于之前提到的排序方法,orderBy 和 orderByCompare,orderByDesc 方法也使用冒泡排序算法来实现排序。
不同之处在于这里是根据元素大小的相反关系(逆序)来进行排序。
接受比较函数参数:

可选参数 $function 表示比较函数,用于自定义排序规则。
如果未提供比较函数,则默认使用小于号(<)进行比较,以实现降序排序。
排序逻辑:

外层循环控制每一轮的比较次数,内层循环处理相邻元素的比较和交换。
根据比较结果(按照提供的比较函数或默认的大小比较符号),决定是否交换两个元素的位置。
返回对象:

将按照降序排序后的数组存储回原始数组 $this->array 中,并返回当前对象本身,以支持链式调用。
通过 orderByDesc 方法,您可以对数组中的元素按照降序顺序进行排序。排序结果将根据提供的比较函数或默认的逆序关系,最终得到按照降序排列的数组。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZH蔚来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值