首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 二維數組去重兩大經典方案:鍵值重組法與鍵名保留法對比

     編輯:PHP 相關知識

PHP 二維數組去重兩大經典方案:鍵值重組法與鍵名保留法對比

PHP array_unique() 僅支持一維數組。針對二維數組去重,業界沉澱出兩大經典方案:方案一:完全重建索引 (適用於順序無關場景)、方案二:保留原鍵名 (適用於業務依賴鍵名場景)。本文深度對比兩者實現、適用場景、性能差異。

方案一:鍵值重組法 (完全重建數字索引)

/**
 * 二維數組去重:重建 0 基數字索引,不保留原鍵名
 * @param array $array2D
 * @return array 去重後數組 (數字索引 0,1,2...)
 */
function array_unique_fb($array2D) {
    foreach ($array2D as $v) {
        $v = join(',', $v);  // 降維:子數組 → 字符串
        $temp[] = $v;
    }
    $temp = array_unique($temp);  // 一維去重
    foreach ($temp as $k => $v) {
        $temp[$k] = explode(',', $v);  // 重組:字符串 → 子數組
    }
    return $temp;
}

特點

  • 輸出索引為 0, 1, 2... 連續數字
  • 原關聯鍵名 (如 'first', 'second') 丟失
  • 代碼極簡,適合「只關心值集合」場景
  • 隱患:分隔符 , 若出現在數據中會導致錯誤拆分

方案二:鍵名保留法 (保留一級鍵,可選保留二級鍵)

/**
 * 二維數組去重:保留一級鍵名,按需保留二級鍵結構
 * @param array $array2D
 * @return array
 */
function array_unique_fb_keep_keys($array2D) {
    foreach ($array2D as $k => $v) {
        $v = join(',', $v);
        $temp[$k] = $v;  // 保留一級鍵
    }
    $temp = array_unique($temp);
    foreach ($temp as $k => $v) {
        $arr = explode(',', $v);
        // 業務特定鍵名映射 (需根據實際結構調整)
        $temp2[$k]['id'] = $arr[0];
        $temp2[$k]['title'] = $arr[1];
        $temp2[$k]['keywords'] = $arr[2];
        $temp2[$k]['content'] = $arr[3];
    }
    return $temp2;
}

特點

  • 保留原一級鍵名 (如 'first', 'third')
  • 二級鍵需硬編碼映射 ($arr[0] → 'id'),通用性差
  • 適用於「鍵名含業務意義」場景 (如數據庫主鍵、配置項標識)
  • 同樣存在分隔符衝突風險

深度對比表

維度方案一:重組法方案二:保留鍵名法
一級鍵保留❌ 重建 0 基索引✅ 保留原鍵名
二級鍵保留✅ 自動保留 (靠 join/explode 位置對應)⚠️ 需硬編碼映射
代碼通用性✅ 高 (無業務耦合)❌ 低 (含具體字段映射)
適用場景數據集合去重、API 返回值清洗配置項去重、主鍵關聯數據去重
分隔符風險⚠️ 同等風險⚠️ 同等風險
性能略快 (無鍵名操作)略慢 (鍵名保留開銷)

核心缺陷:分隔符衝突的根治方案

上述兩方案均使用 join(','),若數據包含逗號會導致 explode 錯誤拆分。生產環境必須使用不可見字符:

$sep = "\x1F";  // Unit Separator (ASCII 31), 極難出現在業務數據中
// 或
$sep = chr(31); // 同義

// 安全版 join/explode
$v = join($sep, $v);
$arr = explode($sep, $v);

進階通用方案:serialize 版 (推薦生產使用)

/**
 * 通用二維/多維數組去重:serialize 序列化法
 * 優勢:無分隔符風險、支持任意嵌套、保留類型、性能優
 * @param array $array
 * @param bool  $keepKeys 是否保留一級鍵
 * @return array
 */
function array_unique_multi($array, $keepKeys = false) {
    if ($keepKeys) $keys = array_keys($array);
    foreach ($array as $k => $v) {
        $temp[$k] = serialize($v);  // 完美保留結構與類型
    }
    $temp = array_unique($temp);
    foreach ($temp as $k => $v) {
        $output[$keepKeys ? $keys[$k] : $k] = unserialize($v);
    }
    return $output;
}

語義去重:按業務字段去重 (最高頻實際需求)

/**
 * 指定字段去重:保留首次出現記錄
 * @param array $data
 * @param string $field
 * @return array
 */
function unique_by_field($data, $field) {
    $seen = [];
    return array_filter($data, function($item) use ($field, &$seen) {
        $val = $item[$field] ?? null;
        if ($val === null) return true;  // 無該字段不參與去重
        if (isset($seen[$val])) return false;
        $seen[$val] = true;
        return true;
    });
}

// 示例:用戶列表按 email 去重
$users = [
    ['id'=>1, 'email'=>'a@test.com', 'name'=>'Alice'],
    ['id'=>2, 'email'=>'b@test.com', 'name'=>'Bob'],
    ['id'=>3, 'email'=>'a@test.com', 'name'=>'Alice2'],  // 重複 email
];
print_r(unique_by_field($users, 'email'));
/* 保留 id=1 的記錄 */

選型決策樹

  1. 需保留一級鍵名? → 是 → 方案二 / serialize 版 keepKeys=true
  2. 數據含嵌套/對象/資源類型? → 是 → serialize 版 (唯一安全選擇)
  3. 純量二維數組、不需保留鍵、數據量中小? → 方案一 (最簡)
  4. 按特定業務字段去重 (如 email/id/手機號)? → unique_by_field() (語義最清晰、O(n) 最優)
  5. 大數據量 (萬級以上)? → serialize 版 / unique_by_field (避免 join/explode 內存峰值)

總結

PHP 二維數組去重沒有銀彈,核心取決於業務對鍵名的依賴程度與數據結構複雜度。現代 PHP (7.2+) 可嘗試 array_unique($arr, SORT_REGULAR) 直接支持多維 (但不保留鍵)。生產環境建議:封裝工具類統一入口,內部路由至 serialize 版或字段去重版,棄用分隔符方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved