Уникальные элементы массива: как избавиться от повторений в PHP

Раздел: Массивы в PHP -> Фильтрация дубликатов

Методы фильтрации дубликатов в массивах PHP

Как получить массив, содержащий только уникальные значения, с помощью встроенной функции?

Наиболее простым и быстрым решением для одномерных массивов является функция array_unique(). Она принимает массив и возвращает новый массив, где каждое значение встречается один раз. При этом ключи первого вхождения сохраняются.

$arr = [1, 2, 2, 3, 'a', 'a'];
$unique = array_unique($arr);
// Результат: [0=>1, 1=>2, 3=>3, 4=>'a']

Php уникальный массив (получение уникальных значений массива в php)

По умолчанию сравнение элементов происходит с приведением типов (SORT_REGULAR). Можно задать флаг для строгого сравнения: SORT_NUMERIC (числовое), SORT_STRING (строковое) или SORT_LOCALE_STRING.

Типичная ошибка: array_unique не работает с многомерными массивами. Если передать массив, содержащий подмассивы, возникнет Warning: "Array to string conversion". Решение – использовать рекурсивную сериализацию (см. варианты ниже).

Цель: быстро получить уникальные значения из одномерного массива с сохранением ключей. Случаи использования: обработка списков ID, тегов, названий.

Как получить уникальные значения с подсчётом количества повторений?

Функция array_count_values() считает вхождения каждого элемента, возвращая ассоциативный массив, где ключами являются значения исходного массива, а значениями – количество повторений. Чтобы получить только уникальные значения, применяется array_keys():

$arr = [1, 2, 2, 3, 1];
$counts = array_count_values($arr);
$unique = array_keys($counts);
// Результат: [0=>1, 1=>2, 2=>3]

Ограничение: array_count_values обрабатывает только строки и целые числа. Для float, null или массивов возникнет Warning. Решение: перед вызовом преобразовать все значения в строки, но это может изменить смысл данных.

Как удалить дубликаты, не используя array_unique, с помощью array_flip?

array_flip() меняет местами ключи и значения. Если в исходном массиве есть повторяющиеся значения, при перевороте останется только последний ключ (или первое вхождение в зависимости от версии PHP). Затем array_keys() возвращает уникальные значения:

$arr = ['apple', 'banana', 'apple', 'cherry'];
$unique = array_keys(array_flip($arr));
// Результат: [0=>'apple', 1=>'banana', 2=>'cherry']

Проблема: значения должны быть валидными ключами (int или string). Для других типов возникает ошибка. Кроме того, порядок может измениться – в новых версиях PHP порядок сохраняется, но полагаться на это не стоит.

Как получить уникальные значения с сохранением исходного порядка вручную?

Цикл foreach с проверкой через in_array или ассоциативный массив сохраняет первое вхождение и порядок:

$arr = [3, 1, 2, 1, 3];
$seen = [];
$unique = [];
foreach ($arr as $v) {
    if (!isset($seen[$v])) {
        $seen[$v] = true;
        $unique[] = $v;
    }
}
// Результат: [0=>3, 1=>1, 2=>2]

Если использовать in_array вместо isset, производительность падает на больших массивах (O(n²)). Всегда используйте ассоциативный массив для быстрой проверки.

Как применить функциональный стиль с array_reduce?

array_reduce позволяет собрать новый массив, добавляя элемент только если он ещё не встречался:

$arr = [1, 2, 2, 3];
$unique = array_reduce($arr, function ($carry, $item) {
    if (!in_array($item, $carry)) {
        $carry[] = $item;
    }
    return $carry;
}, []);
// Результат: [1, 2, 3]

Подходит для функциональных цепочек, но по скорости уступает array_unique.

Та же проблема с производительностью in_array. Альтернатива – передавать через use &$seen, но код усложняется.

Как убрать дубликаты в многомерном массиве?

Стандартные функции не подходят. Используется трюк с сериализацией: каждый элемент массива превращается в строку, применяется array_unique, затем обратное преобразование:

$matrix = [[1,2], [3,4], [1,2], [5,6]];
$unique = array_map('unserialize', array_unique(array_map('serialize', $matrix)));
// Результат: [[1,2], [3,4], [5,6]]

Не работает, если подмассивы содержат ресурсы или объекты, не поддающиеся сериализации. Для таких случаев требуется рекурсивное сравнение.

Как получить уникальные значения с сохранением ключей исходного массива (первые вхождения)?

Комбинация array_unique и array_intersect_key позволяет отфильтровать исходный массив, оставив только элементы с ключами, которые присутствуют в уникальном массиве:

$arr = ['a'=>1, 'b'=>2, 'c'=>1, 'd'=>3];
$uniqueKeys = array_unique($arr);
$result = array_intersect_key($arr, $uniqueKeys);
// Результат: ['a'=>1, 'b'=>2, 'd'=>3]

Как удалить дубликаты, если порядок не важен, используя сортировку?

Сортировка массива и последующий проход с сравнением соседних элементов позволяет избавиться от повторений с минимальным использованием памяти:

$arr = [3, 1, 2, 1, 3];
sort($arr);
$unique = [];
$prev = null;
foreach ($arr as $v) {
    if ($v !== $prev) {
        $unique[] = $v;
        $prev = $v;
    }
}
// Результат: [1, 2, 3]

Происходит потеря исходного порядка и ключей. Подходит, когда порядок не критичен.

Расширенные примеры фильтрации дубликатов

Ниже приведены более сложные и неочевидные сценарии использования методов получения уникальных значений.

Пример 1: array_unique с разными флагами сравнения

Флаги влияют на то, какие элементы считаются дубликатами. Продемонстрируем различия:

Пример
$arr = ['1', 1, 2, '2', '3'];
echo "SORT_REGULAR: ";
print_r(array_unique($arr, SORT_REGULAR));
echo "SORT_NUMERIC: ";
print_r(array_unique($arr, SORT_NUMERIC));
echo "SORT_STRING: ";
print_r(array_unique($arr, SORT_STRING));
SORT_REGULAR: Array ( [0] => 1 [2] => 2 [4] => 3 )
SORT_NUMERIC: Array ( [0] => 1 [2] => 2 [4] => 3 )
SORT_STRING: Array ( [0] => 1 [1] => 2 [2] => 2 [4] => 3 )

Пояснение: SORT_REGULAR считает '1' и 1 разными? В старых версиях PHP они считались одинаковыми, в новых – могут быть разными из-за строгого сравнения. SORT_NUMERIC приводит к числу, '1' и 1 совпадают. SORT_STRING приводит к строке, '2' и 2 разные.

Пример 2: Сохранение ключей с помощью array_intersect_key

Если исходный массив имеет строковые ключи, полезно сохранить их после удаления дубликатов:

Пример
$data = [
    'first' => 'apple',
    'second' => 'banana',
    'third' => 'apple',
    'fourth' => 'cherry'
];
$unique = array_intersect_key($data, array_unique($data));
print_r($unique);
Array ( [first] => apple [second] => banana [fourth] => cherry )

Пример 3: Удаление дубликатов объектов по свойству

Если массив состоит из объектов, стандартные функции не подходят. Используем цикл с проверкой свойства:

Пример
class Item {
    public $id;
    public $name;
    public function __construct($id, $name) {
        $this->id = $id;
        $this->name = $name;
    }
}
$items = [
    new Item(1, 'A'),
    new Item(2, 'B'),
    new Item(1, 'A'),
    new Item(3, 'C')
];
$seen = [];
$uniqueItems = [];
foreach ($items as $item) {
    if (!isset($seen[$item->id])) {
        $seen[$item->id] = true;
        $uniqueItems[] = $item;
    }
}
echo count($uniqueItems); // 3

Пример 4: Рекурсивное удаление дубликатов из многомерного массива без сериализации

Для массивов, содержащих вложенные массивы, сериализация может быть ненадёжной. Напишем рекурсивную функцию сравнения:

Пример
function recursiveUnique($array) {
    $result = [];
    foreach ($array as $element) {
        if (is_array($element)) {
            $element = recursiveUnique($element);
        }
        if (!in_array($element, $result, true)) {
            $result[] = $element;
        }
    }
    return $result;
}
$nested = [[1,2], [3,[4,5]], [1,2], [3,[4,5]]];
$uniqueNested = recursiveUnique($nested);
print_r($uniqueNested);
Array ( [0] => Array ( [0] => 1 [1] => 2 ) [1] => Array ( [0] => 3 [1] => Array ( [0] => 4 [1] => 5 ) ) )

Пояснение: функция обрабатывает вложенные массивы рекурсивно, используя строгое сравнение (===). Для больших массивов может быть медленной.

Пример 5: Комбинирование array_unique и array_values для переиндексации

После array_unique ключи остаются разрозненными. Чтобы получить последовательные числовые ключи, применяется array_values:

Пример
$arr = ['x'=>1, 'y'=>2, 'z'=>1];
$unique = array_values(array_unique($arr));
print_r($unique);
Array ( [0] => 1 [1] => 2 )

Пример 6: Использование array_filter со статической переменной

Можно применить array_filter с анонимной функцией, которая сохраняет увиденные значения через статическую переменную:

Пример
$arr = [1, 2, 2, 3, 1];
$unique = array_filter($arr, function($v) {
    static $seen = [];
    if (isset($seen[$v])) return false;
    $seen[$v] = true;
    return true;
});
print_r(array_values($unique));
Array ( [0] => 1 [1] => 2 [2] => 3 )

Пояснение: статическая переменная сохраняет состояние между вызовами callback. Удобно, если нужно получить уникальные значения без создания внешнего массива.

получение уникальных значений массива в PHP - comments

En
Php уникальный массив (php)