ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

php对很大的二维数组做去重和求差集操作:array_filter太慢,array_map配合array_diff速度最快

2022-08-19 10:30:48  阅读:160  来源: 互联网

标签:map arr 求差 数组 time diff array data


需求:

1个长库10万级别的二维数组,元素内数组长度10个左右(其实就是一个数据表的结果集合),根据指定字段对数据进行去重,最后要得到去重后被丢弃的数据明细。

 

两个关键过程:

过程1 - 根据指定字段对数组内元素进行去重:

function arrayUniqueByKey(array $arr, string $key): array
{
    $arr = array_reverse($arr);         // 数组倒置保留重复的第1个元素,如果不倒置就是保留重复的最后1个元素
    if (isset($arr[0][$key])) {
        foreach ($arr as $v) {
            $newArr[$v[$key]] = $v;
        }
    }
    $newArr = isset($newArr) ? array_values($newArr) : [];
    $newArr = array_reverse($newArr);   // 前面倒置了,后面就再给倒回去
    return $newArr;
}

简单说明:遍历1次数组是必须的,遍历过程中只是拿关键字段的值当作键名去创建一个新数组,这样当关键字段重复时,赋值就相当于覆盖,进而实现去重。

 

过程2 - 求原数组和被去重后数组的差集:

function arrayDiff(array $arr1, array $arr2): array
{
    $arr1 = array_map(function ($v) {
        return json_encode($v);
    }, $arr1);
    $arr2 = array_map(function ($v) {
        return json_encode($v);
    }, $arr2);
    $diff = array_diff($arr1, $arr2);
    $diff = array_map(function ($v) {
        return json_decode($v, true);
    }, $diff);
    return array_values($diff);
}

简单说明:先把两个多维数组转成一维数组,再用array_diff()求得一维数组差集,最后把一维差集再转回多维。

 

模拟测试:

<?php
/**
 * 得到系统当前毫秒级时间的各种表示
 *
 * @author Aaron <chenqiang@h024.cn>
 */
function getSystemTimes()
{
    list($usec, $sec) = explode(" ", microtime());
    $microtime = ((float)$usec + (float)$sec);
    $time = (int)floor($microtime);
    $millsecond = round($microtime - $time, 3) * 1000;
    $millsecond = str_pad($millsecond, 3, '0', STR_PAD_LEFT);
    $weekarray = array("日", "一", "二", "三", "四", "五", "六");
    $data['year'] = date('Y', $time);
    $data['month'] = date('m', $time);
    $data['day'] = date('d', $time);
    $data['hour'] = date('H', $time);
    $data['hour_pre'] = date('A', $time);
    $data['hour_12'] = date('h', $time);
    $data['minute'] = date('i', $time);
    $data['second'] = date('s', $time);
    $data['millisecond'] = $millsecond;
    $data['date'] = date('Y-m-d', $time);
    $data['time'] = date('H:i:s', $time);
    $data['weekday'] = "星期{$weekarray[date('w',$time)]}";
    $data['weekday_index'] = date('w', $time);
    $data['time_milli'] = "{$data['time']}.{$millsecond}";
    $data['datetime'] = date('Y-m-d H:i:s', $time);
    $data['datetime_milli'] = "{$data['datetime']}.{$millsecond}";
    $data['timestamp'] = $time;
    $data['timestamp_micro'] = $microtime;
    return $data;
}

/**
 * 二维数组针对指定键名去重
 *
 * @author Aaron <chenqiang@h024.cn>
 *
 * @param array $arr
 * @param string $key
 *
 * @return array
 */
function arrayUniqueByKey(array $arr, string $key): array
{
    $arr = array_reverse($arr);         // 数组倒置保留重复的第1个元素,如果不倒置就是保留重复的最后1个元素
    if (isset($arr[0][$key])) {
        foreach ($arr as $v) {
            $newArr[$v[$key]] = $v;
        }
    }
    $newArr = isset($newArr) ? array_values($newArr) : [];
    $newArr = array_reverse($newArr);   // 前面倒置了,后面就再给倒回去
    return $newArr;
}

/**
 * 求两个多维数组的差集(两个参数别弄反了)
 *
 * @author Aaron <chenqiang@h024.cn>
 *
 * @param array $arr1
 * @param array $arr2
 *
 * @return array    返回$arr1-$arr2的结果
 */
function arrayDiff(array $arr1, array $arr2): array
{
    $arr1 = array_map(function ($v) {
        return json_encode($v);
    }, $arr1);
    $arr2 = array_map(function ($v) {
        return json_encode($v);
    }, $arr2);
    $diff = array_diff($arr1, $arr2);
    $diff = array_map(function ($v) {
        return json_decode($v, true);
    }, $diff);
    return array_values($diff);
}

$arr = [];
echo "\n生成数组开始: " . getSystemTimes()['datetime_milli'];
for ($i = 0; $i < 99999; $i++) {
    $index = $i;
    if ($i % 101 == 0) {
        $index = $i - 1;
    }
    $suffix = str_pad($index, 8, '0', STR_PAD_LEFT);
    if ($index % 113 == 0) {
        $suffix = str_pad($index - 1, 8, '0', STR_PAD_LEFT);
    }
    $arr[] = [
        'name' => '优优' . $index,
        'phone' => "133{$suffix}",
        'var1' => $index,
        'var2' => '',
        'var3' => '',
        'var4' => '',
        'var5' => $index,
    ];
}
echo "\n生成数组完成: " . getSystemTimes()['datetime_milli'];
echo "\n键名去重开始: " . getSystemTimes()['datetime_milli'];
$arr2 = arrayUniqueByKey($arr, 'phone');
echo "\n键名去重完成: " . getSystemTimes()['datetime_milli'];
echo "\n去重求差开始: " . getSystemTimes()['datetime_milli'];
$diff = arrayDiff($arr, $arr2);
echo "\n去重求差完成: " . getSystemTimes()['datetime_milli'];
echo "\n";
var_dump(count($diff));

 

运行结果:

php temp.php 

生成数组开始: 2022-08-19 10:08:54.975
生成数组完成: 2022-08-19 10:08:55.335
键名去重开始: 2022-08-19 10:08:55.335
键名去重完成: 2022-08-19 10:08:55.643
去重求差开始: 2022-08-19 10:08:55.643
去重求差完成: 2022-08-19 10:08:56.320
int(876)

 

从结果可以看到,数据量是99999,生成模拟数据大概花了400ms,去重花的时间大概是300ms,求差集花的时间大概是700ms,去重+求差大约在1秒内完成,这个时效对于这个数据量来说还是可以接受的。

 

总结:

原生数组操作函数的性能一般都是很高的,能用原生就尽量用原生。

用array_map加工数组元素的时间效率很高;

用array_diff求数组差集的时间效率很高;

用array_reverse得到倒置数组的时间效率很高;

 

其他:

对多维数组求差过程特别说明一下,有人说用array_filter和in_array去实现,看上去代码很简洁,但是实际测试时发现性能极差,那段代码是下面这样的,感兴趣可自行测试:

$r = array_filter($arr1, function ($v) use ($arr2) {   return !in_array($v, $arr2); }); 或者 foreach ($all_wechat as $k => $v) {   if (in_array($v, $select_wechat)) {     unset($all_wechat[$k]);   } };

 

标签:map,arr,求差,数组,time,diff,array,data
来源: https://www.cnblogs.com/chenqiang001/p/16601145.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有