PHP 不定个数 de 数组取交集

需求

最近小程序上有个需求,需要对一个文章列表根据多个标签进行筛选。

articles article_tags tags
id article_id id
  tag_id

一个简单的多对多关联模型关系

解决方案

需求:根据选中的多个标签查询满足条件的文章。
一开始我的做法是

$article_ids = DB::table('article_tags')->whereIn('tag_id', $tag_ids)->pluck('article_id')->all(); // 满足条件的文章ID

后来跟前端联调时发现逻辑不对,需要取出同时拥有这些标签的文章,而不是拥有这些标签的所有文章。满足条件的是从不定个数的数组中取交集。
经过一番搜索,有老铁使用了 PHP 中的函数 array_intersect_assoccall_user_func_array 来实现。

$arr1 = ["16","2","3","6","9","17"];
$arr2 = ["16","2","3","9","15"];
$arr3 = ["16","2","3","6","8","17"];
$result_array = call_user_func_array('array_intersect_assoc', array($arr1, $arr2,$arr3));
echo '<pre>';
print_r($result_array);// ["16","2","3"]

看起来这个做法没甚问题,但当我运用到项目中时,却怎么都得不到正确的结果。去翻了手册array_intersect_assoc() 返回一个数组,该数组包含了所有在 array1 中也同时出现在所有其它参数数组中的值。注意和 array_intersect() 不同的是键名也用于比较。原来这函数是键值都需要匹配,但是我的需求只是值相等,取交集。
最后以下做法实现了功能需求。

$article_ids = [];
if ($tag_ids) {
    foreach ($tag_ids as $key => $tag_id) {
        $id = DB::table('article_tags')
                    ->where('tag_id', $tag_id)
                    ->pluck('article_id')
                    ->all(); // 符合标签条件的文章ID
        if ($key === 0) {
            $article_ids = $id;
            continue;
        }
        $article_ids = array_intersect($article_ids, $id); // 计算两数组的交集
    }
}
return $article_ids;

总结

array_intersect — 计算数组的交集
array_intersect_assoc — 带索引检查计算数组的交集
call_user_func_array() — 调用回调函数,并把一个数组参数作为回调函数的参数

参考文章:

PHP取不定个数数组交集

抛砖引玉,假如有更好的做法请告知,求知若渴。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1
$article_ids=collect();
Tag::with('articles.id')
    ->whereIn('id',$tag_ids)
    ->get('id')
    ->map(function ($tag) use ($article_ids) {
            $article_ids = $article_ids
                        ? $tag->articles->pluck('id')->intersect($article_ids)
                        : $tag->articles->pluck('id');
    })
4年前 评论
qf-Z (楼主) 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!