PHP二维数组合并排重的两种方式

业务中需要统计一段时间投票独立的用户数,涉及到数组的排重,用传统array_unique()发现,当数据量达到百万级后, 设置的1G内存都耗尽了,仍然没有统计完。而用array_flip()发现不仅可以统计出来,而且更快。

之前这两种方式没有比较过,数据量小的时候也没有遇到问题,发现差异,一直混用。特记录下两种方式。

待排重的二维数组简化格式如下:

$date_uids = [
            '20190201' => ['6367662430', '6367662430', '5304950359', '5955228171', '6557239611'],
            '20190202' => ['6367662430', '3699970002', '6619393423', '6026157677', '5476921392'],
        ];

方法一: 使用array_merge()结合array_unique()。
在遍历中array_merge()、array_unique()特别耗内存, 第9行,当以下count($uids) = 180万的时候,1G内存耗尽

// array_unique();
function distinct_uid_by_array_unique($datas) {
        $uids = [];
        foreach ($datas as $data) {
                if (empty($data)) {
                        continue;
                }
                // 考虑先对$dara 使用array_unique()在合并。
                $uids = array_unique(array_merge($uids, (array)$data));
        }

        return count($uids);
}

方法二:使用array_flip()和数组+合并。
去重总数为4572684,没有出现内存耗尽问题。

// array_flip();
function distinct_uid_by_array_flip($datas) {
        $uids = [];
        foreach ($datas as $data) {
                if (empty($data)) {
                        continue;
                }
                $uids += array_flip($data);
        }

        return count($uids);
}

以上都是直观感受,具体执行时间差异和内存占用差异,还有待对比。针对一维数组排重array_unique()和array_flip()比较,傲雪星枫有一组比较数据,array_flip方法去重比使用array_unique方法运行时间减少98%,内存占用减少4/5,可参考比较细节:《php 数组元素快速去重》

综上,在实际开发中,遇到排重的情况,优先使用array_flip(),尽量不考虑array_unique()。

完整示例:

$date_uids = [
            '20190201' => ['6367662430', '6367662430', '5304950359', '5955228171', '6557239611'],
            '20190202' => ['6367662430', '3699970002', '6619393423', '6026157677', '5476921392'],
            '20190203' => ['6367662430', '5971792803', '5516939770', '6579480643', '6399312379'],
        ];

// array_unique();
function distinct_uid_by_array_unique($datas) {
	$uids = [];
	foreach ($datas as $data) {
		if (empty($data)) {
			continue;
		}
		$uids = array_unique(array_merge($uids, (array)$data));
	}

	return count($uids);
}

// array_flip();
function distinct_uid_by_array_flip($datas) {
	$uids = [];
	foreach ($datas as $data) {
		if (empty($data)) {
			continue;
		}
		$uids += array_flip($data);
	}

	return count($uids);
}

$count = $total = 0;
if (!empty($date_uids) && is_array($date_uids)) {
	$count = distinct_uid_by_array_unique($date_uids);
	$total = distinct_uid_by_array_flip($date_uids);
}

var_dump($count, $total);die; // 12 12

注:另外发现MySQL distinct有两种写发

select count(distinct(fan_uid)) from energy_fan_feed_0972;
select count(distinct fan_uid) from energy_fan_feed_0972;

发表评论

电子邮件地址不会被公开。 必填项已用*标注