分割数组的几种方法比较
需求:
前段时间遇到一个需求,批量同步数据。
给过来的数据如果本地已经有的就更新,没有的就创建。
分析
因为数据有差异,不能进行覆盖因此mysql的 REPLACE INTO 是不考虑了,
这时候,我需要把传过来的数据进行分离,分离成两个组,一个更新组,一个插入组。
首先来构建一下假数据
//源数据
$origin =[];
//当前本地数据
$current=[];
//生成10000个数据
for($i=1;$i<10000;$i++) {
$origin[] = ['id' => $i, 'title' => 'title'.$i, 'content' => 'name'.$i];
}
//假设本地的数据已经取好了,我用title来作为唯一值来处理吧,容易认一点
for($i=5000;$i<8000;$i++) {
$current[] = 'title'.$i;
}
第一种使用foreach遍历
$t1 = microtime(true);
$insertArr = [];
$updateArr = [];
foreach ($origin as $k=>$value) {
if (!in_array($value['title'], $current)) {
$insertArr[] = $value;
}else {
$updateArr[] = $value;
}
}
$t2 = microtime(true);
dd($t2 - $t1);
代码执行时间:0.10883212089539
第二种使用array_map或array_walk进行遍历
$t1 = microtime(true);
array_walk($origin, function($value) use ($current, &$insertArr, &$updateArr) {
if (!in_array($value['title'], $current)) {
$insertArr[] = $value;
} else {
$updateArr[] = $value;
}
});
或者
array_map(function($value) use ($current, &$insertArr, &$updateArr) {
if (!in_array($value['title'], $current)) {
$insertArr[] = $value;
} else {
$updateArr[] = $value;
}
}, $origin);
$t2 = microtime(true);
dd($t2 - $t1);
两个执行时间差不多都是这个:0.11882400512695
第三种:array_diff_key交集比较
$t1 = microtime(true);
//把title取出来做为键
//$origin_new = array_combine(array_column($origin, 'title'), $origin);
$origin_new = array_column($origin, null, 'title');
//把值作为键
$current_new = array_flip($current);
//需要新增插入的数据 (用键来做差集比较得出新的源)
$insertArr = array_diff_key($origin_new, $current_new);
//需要进行更新的数据
$updateArr = array_diff_key($origin_new, $new_origin);
$t2 = microtime(true);
dd($t2 - $t1);
代码执行时间:0.0013279914855957
以上代码执行后分离的数组都得到以下相同的数据
//打印数组
dd($insertArr, $updateArr);
分离出的需要插入的数组
array:7000 [
"title1" => array:3 [▼
"id" => 1
"title" => "title1"
"content" => "name1"
]
"title2" => array:3 [▶]
"title3" => array:3 [▶]
...
"title4999" => array:3 [ …3]
"title8000" => array:3 [ …3]
"title8001" => array:3 [ …3]
...
"title9999" => array:3 [ …3]
"title10000" => array:3 [ …3]
]
分离出来的需要更新的数据
array:3000 [▼ "title5000" => array:3 [▼ "id" => 5000 "title" => "title5000" "content" => "name5000" ] "title5001" => array:3 [▶] "title5002" => array:3 [▶] ... "title7998" => array:3 [ …3] "title7999" => array:3 [ …3] ]
总结
foreach、 array_map、 array_walk 这些需要遍历的都比不过通过 array_diff_key 数组键去对比取交集的方法。
选择 array_diff_key 效率是最快的
以下进行封装:
/**
* 对比法分割数组
*
* @param $key 通过指定键(key)去对比
* @param $origin 原数组
* @param $split 分割数组 (源数组中的某个键的值)
* @return array ['split'=>被分割出来的数组, 'remainders'=>剩余的数据];
*/
function splitArr($key, $origin, $split)
{
//把title取出来做为键
//$origin_new = array_combine(array_column($origin, $key), $origin);
$origin_new = array_column($origin, null, $key);
//把值作为键
$split_flip = array_flip($split);
//剩余的源数据 (用键来做差集比较得剩余的源数据)
$remainders = array_diff_key($origin_new, $split_flip);
//被分割出来的数据
$new_split = array_diff_key($origin_new, $remainders);
return ['split'=>$new_split, 'remainders'=>$remainders];
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: