常見 `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
)
*/
?>
<?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));
?>
<?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
)
*/
?>
<?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 個不重複
?>
<?php
$pool = range(1, 30);
$keys = array_rand($pool, 10); // 取 10 個隨機鍵
$result = array_intersect_key($pool, array_flip((array)$keys));
print_r($result);
?>
<?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` 旗標 | - | - |
PHP 合併相同陣列元素,**核心工具箱**只有三樣:
針對**多維/物件**資料,統一模式:建立「看見表」(Seen Map) 鍵為去重依據值,遍歷過濾。根據「順序要求、資料型別、量級大小」選擇最適策略,即能優雅解決所有去重合併需求。