PHP 不定個數 de 陣列取交集

qf-Z發表於2020-01-20

最近小程式上有個需求,需要對一個文章列表根據多個標籤進行篩選。

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 協議》,轉載必須註明作者和本文連結

相關文章