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

PHP 陣列去重進階:合併相同元素只保留一個的多種實現

     編輯:PHP 綜合知識

前言:不只是「去重」,是「合併同類項」

常見 `array_unique()` 只是移除重複值。但實務上常需:**將相同值合併為一個、保留原始順序、或按特定規則合併**。本文探討多種「合併相同元素」的實現策略,從內建函數到自訂演算法。

方法一:排序 + 相鄰比較 (保留首次出現、結果有序)

<?php
function mergeDuplicatesSorted(array $array): array {
    if (empty($array)) return [];
    
    // 複本排序,不影響原陣列
    $sorted = $array;
    sort($sorted, SORT_REGULAR); // 保持型別比較
    
    $result = [];
    $prev = null;
    $first = true;
    
    foreach ($sorted as $value) {
        if ($first || $value !== $prev) {
            $result[] = $value;
            $prev = $value;
            $first = false;
        }
    }
    return $result;
}

$data = ['aa', 'bb', 'aa', 3, 4, 5, 5, 5, 5, 'bc'];
print_r(mergeDuplicatesSorted($data));
/*
Array
(
    [0] => 3
    [1] => 4
    [2] => 5
    [3] => aa
    [3] => bb
    [4] => bc
)
*/
?>
  • **優點**:O(n log n) 排序 + O(n) 掃描,邏輯簡單、不需額外哈希表。
  • **缺點**:**改變原始順序**,結果為排序後順序。
  • **適用**:不在乎順序、需結果有序、資料可排序比較。

方法二:array_unique() 內建函數 (保留首次出現順序)

<?php
$data = ['aa', 'bb', 'aa', 3, 4, 5, 5, 5, 5, 'bc'];
$result = array_unique($data);
print_r($result);
/*
Array
(
    [0] => aa
    [1] => bb
    [3] => 3
    [4] => 4
    [5] => 5
    [9] => bc
)
*/
// 鍵值保留原索引,如需重新索引:
$result = array_values(array_unique($data));
?>
  • **優點**:一行程式碼、**保留首次出現順序**、C 底層實現極快。
  • **注意**:預設 `SORT_STRING` 比較,`1` 和 `'1'` 視為相同。嚴格型別用 `array_unique($data, SORT_REGULAR)`。
  • **適用**:多數一般去重需求、保留順序。

方法三:翻轉鍵值法 (利用陣列鍵唯一性、極快)

<?php
function mergeFlip(array $array): array {
    // 翻轉:值變鍵,重複值自動覆蓋 (保留最後一次出現)
    $flipped = array_flip($array);
    // 再翻回:鍵變值,得到去重陣列 (順序為最後出現順序)
    return array_flip($flipped);
}

$data = ['aa', 'bb', 'aa', 3, 4, 5, 5, 5, 5, 'bc'];
print_r(mergeFlip($data));
/* 保留最後出現順序:
Array
(
    [0] => bb
    [1] => aa
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => bc
)
*/
?>
  • **原理**:陣列鍵唯一,`array_flip` 遇到重複值後者覆蓋前者。
  • **特點**:**保留最後一次出現順序**,速度極快 (兩次 O(n) 線性)。
  • **限制**:值必須為合法鍵類型 (int/string),物件/陣列/浮點數需轉換。

方法四:mt_rand + 陣列鍵去重 (大範圍隨機不重複)

<?php
function uniqueRandomInts(int $min, int $max, int $count): array {
    if ($count > ($max - $min + 1)) throw new Exception("超出範圍");
    
    $result = [];
    // 使用鍵去重:$result[$num] = true
    while (count($result) < $count) {
        $num = mt_rand($min, $max);
        $result[$num] = true; // 自動去重
    }
    return array_keys($result);
}

print_r(uniqueRandomInts(1, 1000000, 10)); // 1~100萬取 10 個不重複
?>
  • **核心技巧**:利用陣列鍵 **O(1) 查找/去重** 特性,避免 `in_array` O(n) 掃描。
  • **適用**:**大範圍、少量抽樣**,記憶體極省。

方法五:array_rand() 從候選池抽樣

<?php
$pool = range(1, 30);
$keys = array_rand($pool, 10); // 取 10 個隨機鍵
$result = array_intersect_key($pool, array_flip((array)$keys));
print_r($result);
?>
  • **注意**:`array_rand` 回傳**鍵**,需 `array_intersect_key` 取值。
  • **陷阱**:`range(1, 100, 2)` 步長非 1 時,陣列長度非 100,第二參數不可超過實際長度。

進階:多維陣列去重 (按特定欄位合併)

<?php
function uniqueByKey(array $items, string $key): array {
    $seen = [];
    return array_filter($items, function($item) use ($key, &$seen) {
        $val = $item[$key] ?? null;
        if (isset($seen[$val])) return false;
        $seen[$val] = true;
        return true;
    });
}

$users = [
    ['id' => 1, 'email' => 'a@test.com'],
    ['id' => 2, 'email' => 'b@test.com'],
    ['id' => 3, 'email' => 'a@test.com'], // 重複 email
];
print_r(uniqueByKey($users, 'email'));
/* 保留首次出現:
Array
(
    [0] => Array ( [id] => 1 [email] => a@test.com )
    [1] => Array ( [id] => 2 [email] => b@test.com )
)
*/
?>

進階:物件去重 (按屬性/方法)

<?php
class User {
    public $id, $email;
    public function __construct($id, $email) { $this->id=$id; $this->email=$email; }
}

$users = [new User(1,'a@x'), new User(2,'b@x'), new User(3,'a@x')];

$seen = [];
$result = array_filter($users, function($u) use (&$seen) {
    if (isset($seen[$u->email])) return false;
    $seen[$u->email] = true;
    return true;
});
?>

效能對比與選擇指南

場景推薦方法時間複雜度順序保留
一般陣列去重、保留首次順序`array_unique($arr, SORT_REGULAR)`O(n)首次出現順序
需結果有序 (字母/數值)`sort + 相鄰比較`O(n log n)排序順序
保留最後出現順序、極速`array_flip(array_flip($arr))`O(n)最後出現順序
大範圍隨機抽樣不重複`mt_rand + 鍵去重`O(k) 期望隨機順序
多維陣列/物件按欄位去重`array_filter + 看見表`O(n)首次出現順序
嚴格型別區分 1 vs '1'加 `SORT_REGULAR` 旗標--

常見陷阱提醒

  • 浮點數鍵:`array_flip` 不支援 float 鍵,會轉為 int (截斷)。解決:`sprintf('%.10F', $val)` 轉字串。
  • 物件/陣列值:無法直接作鍵。解決:`spl_object_id()` (物件) 或 `serialize()`/`json_encode()` (陣列) 轉字串。
  • 大小寫敏感:`array_unique` 預設大小寫敏感。不敏感需自行 `array_map('strtolower', $arr)` 處理。
  • 參考保留:`array_unique` 不保留參考關係。

總結

PHP 合併相同陣列元素,**核心工具箱**只有三樣:

  1. array_unique() —— 通用首選,保留首次順序。
  2. array_flip() 雙翻 —— 極速、保留最後順序、值須為標量。
  3. 排序 + 掃描 —— 結果有序、可處理不可哈希值。

針對**多維/物件**資料,統一模式:建立「看見表」(Seen Map) 鍵為去重依據值,遍歷過濾。根據「順序要求、資料型別、量級大小」選擇最適策略,即能優雅解決所有去重合併需求。

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