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

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

Пример массива:

Array
(
    [0] => Array
    (
        [0] => abc
        [1] => def
    )

    [1] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [2] => Array
    (
        [0] => mno
        [1] => pql
    )

    [3] => Array
    (
        [0] => abc
        [1] => def
    )

    [4] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [5] => Array
    (
        [0] => mno
        [1] => pql
    )

)
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
330
0
271 602
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

Комментарии пользователей к документации array_unique () предлагают множество решений для этого. Вот один из них:

kenrbnsn at rbnsn dot com
27-Sep-2005 12:09

Yet another Array_Unique for multi-demensioned arrays. I've only tested this on two-demensioned arrays, but it could probably be generalized for more, or made to use recursion.

This function uses the serialize, array_unique, and unserialize functions to do the work.


function multi_unique($array) {
    foreach ($array as $k=>$na)
        $new[$k] = serialize($na);
    $uniq = array_unique($new);
    foreach($uniq as $k=>$ser)
        $new1[$k] = unserialize($ser);
    return ($new1);
}

Это от http://ca3.php.net/manual/en/function.array-unique.php#57202.

Другой путь. Также сохранит ключи.

function array_unique_multidimensional($input)
{
    $serialized = array_map('serialize', $input);
    $unique = array_unique($serialized);
    return array_intersect_key($input, $unique);
}

Для больших массивов этот метод часто как минимум на 50% быстрее принятого ответа.

Lorien Brune 13.05.2020 23:28
Ответ принят как подходящий

Вот еще один способ. Промежуточные переменные не сохраняются.

Мы использовали это, чтобы исключить дублирование результатов из множества перекрывающихся запросов.

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

Из-за десериализации это медленнее и медленнее, чем больше и сложнее массив. Есть причина, по которой я использовал array_intersect_key (за полгода до этого ответа).

OIS 09.02.2013 03:00

@OIS, я думаю, они хотели один лайнер. нужно было просто переписать как $ no-duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize'), $ array));

trevorkavanaugh 04.06.2013 00:17

@OIS хорошо протестировал его, была опечатка, но он работает ... спасибо, чувак !: $ no_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array)));

trevorkavanaugh 04.06.2013 00:26

если вы хотите, чтобы индекс был непрерывным, используйте array_values, т.е. $ input = array_values ​​(array_map ("unserialize", array_unique (array_map ("serialize", $ input))));

lbsweek 17.04.2014 14:44

В настоящее время вы, вероятно, выберете json_encode и json_decode вместо сериализации PHP. должен иметь преимущества для значений, предоставленных и, которые вы не сталкиваетесь с деталями сериализации PHP, которые сериализуются / десериализованы, поставляются с и, скорее всего, являются нежелательными.

hakre 23.08.2014 17:38

$ input = array_values ​​($ input); Чтобы исправить отсутствующие ключи массива внутри массива

Dhawal Naik 28.08.2015 17:06

Хотя это круто, я не хочу зависеть от serialize и unserialize. То, как это реализовано в PHP, несколько раз менялось за кулисами. Дольше всего ссылок не хранилось. Сейчас они есть, но только на ссылки в сериализованном массиве. (Я знаю, что в вопросе не было объектов). Лучше всего будет array_unique($input, SORT_REGULAR) или какая-нибудь пользовательская функция.

Michael 23.01.2016 18:51

Помните, что serialize(array('a' => '1', 'b' => '1')) отличается от serialize(array('b' => '1', 'a' => '1')). Эта опция не работает для массивов, используемых как sets или (hash)maps.

Andras Gyomrey 19.10.2016 17:49

Еще лучше с одиночными запятыми! $input = array_map('unserialize', array_unique(array_map('serialize', $input)));

Heitor 23.08.2017 11:23

@Michael - Из текущего документа PHP: «Обратите внимание, что array_unique () не предназначен для работы с многомерными массивами».

gmeben 08.03.2018 22:03

Хороший ответ, но он не поддерживает записи с другим порядком, например [['foo', 'bar'], ['bar', 'foo']]. Чтобы использовать ваш фрагмент, я отсортировал дочерние массивы.

AFA Med 19.06.2018 16:32

Легко читаемое решение, возможно, не самое эффективное:

function arrayUnique($myArray){
    if (!is_array($myArray))
        return $myArray;

    foreach ($myArray as &$myvalue){
        $myvalue=serialize($myvalue);
    }

    $myArray=array_unique($myArray);

    foreach ($myArray as &$myvalue){
        $myvalue=unserialize($myvalue);
    }

    return $myArray;

} 

У меня была аналогичная проблема, но я нашел для нее 100% рабочее решение.

<?php
    function super_unique($array,$key)
    {
       $temp_array = [];
       foreach ($array as &$v) {
           if (!isset($temp_array[$v[$key]]))
           $temp_array[$v[$key]] =& $v;
       }
       $array = array_values($temp_array);
       return $array;

    }


$arr = "";
$arr[0]['id']=0;
$arr[0]['titel'] = "ABC";
$arr[1]['id']=1;
$arr[1]['titel'] = "DEF";
$arr[2]['id']=2;
$arr[2]['titel'] = "ABC";
$arr[3]['id']=3;
$arr[3]['titel'] = "XYZ";

echo "<pre>";
print_r($arr);
echo "unique*********************<br/>";
print_r(super_unique($arr,'titel'));

?>

Это отвечает на другой вопрос. Смотрите здесь: stackoverflow.com/questions/4585208/…

OIS 09.02.2013 03:28

Отличная функция! и если вы имеете дело с объектами: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;

Playnox 17.03.2016 22:06

Начиная с 5.2.9 вы можете использовать array_unique(), если вы используете флаг SORT_REGULAR следующим образом:

array_unique($array, SORT_REGULAR);

Это заставляет функцию сравнивать элементы на равенство, как если бы использовался $a == $b, что идеально подходит для вашего случая.

Выход

Array
(
    [0] => Array
        (
            [0] => abc
            [1] => def
        )

    [1] => Array
        (
            [0] => ghi
            [1] => jkl
        )

    [2] => Array
        (
            [0] => mno
            [1] => pql
        )

)

Однако имейте в виду, что документация утверждает:

array_unique() is not intended to work on multi dimensional arrays.

Думаю, это более быстрое и понятное решение, чем принятое! давайте проголосуем за это! :) Хммм на сайте php мы видим, что это не так быстро, как я думал ...

Andron 05.05.2015 13:50

Странно, что использование флага SORT_REGULAR просто не работает для меня, чтобы удалить повторяющиеся массивы.

Stefan 30.07.2015 11:28

@Stefan, тогда ты можешь задать новый вопрос.

Ja͢ck 30.07.2015 12:00

На этот вопрос уже есть другие рабочие ответы, которые я проверил (см., Например, принятый ответ). Я просто не могу проверить этот конкретный ответ для моего конкретного примера.

Stefan 30.07.2015 12:05

@Stefan, не могли бы вы предоставить pastebin для решения вашей конкретной проблемы? Просто сказать мне, что это не работает, не поможет мне понять.

Ja͢ck 30.07.2015 12:06

@Stefan Ты прав; похоже, что он не дает правильных результатов, но, вероятно, это ошибка, потому что работает с PHP 7 = /

Ja͢ck 30.07.2015 12:25

Очень интересно ... Большое спасибо, Джек, за внимание к этому - потрясающий ответ. В любом случае, поскольку я не могу изменить версию php на сервере, мне просто нужно будет использовать одно из других решений.

Stefan 30.07.2015 12:28

В моем случае это тоже работает, но кого-нибудь еще беспокоит эта заметка в документе array_unique ()? php.net/manual/en/…

Arleigh Hix 02.05.2016 21:46

@Jack Вы правы, это ошибка в PHP 5.6.23: eval.in/645675, но исправлена ​​в PHP 7.0.8: eval.in/645676

Zack Morris 21.09.2016 04:40

Будьте осторожны, array(1, 2) отличается от array(2, 1). Это не сработает для массивов, используемых как sets.

Andras Gyomrey 19.10.2016 17:53

@AndrasGyomrey, если вы хотите выразить множества с помощью массивов, вы должны нормализовать их.

Ja͢ck 19.10.2016 17:55

Либо вы используете in_array, либо убедитесь, что ваши элементы можно использовать как ключи массива (сериализуемые), и вы используете какое-то фиктивное значение массива. Это зависит от вашей реализации. Для первой реализации вы не можете использовать этот подход.

Andras Gyomrey 20.10.2016 11:57

Это правильное решение по сравнению с сериализацией / десериализацией ответа. Обратите внимание, что уникальный массив выполняется довольно быстро по сравнению с сериализацией / десериализацией. Этот мощь будет проблемой, если вы сделаете сотни / тысячи уникальных массивов.

PeterM 12.10.2017 22:09

Обратите внимание, что это вызывает странное поведение с ассоциированными массивами, которые имеют логические истинные значения (они исчезают). Пример: 3v4l.org/Yj6Y1 (пропал show_in_configurator).

Ken 10.03.2021 16:03

Альтернатива сериализации и уникальности

$test = [
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
];

$result = array_reduce(
    $test,
    function($carry,$item){
        if (!in_array($item,$carry)) {
            array_push($carry,$item);
        }
        return $carry;
    },
    []
);

var_dump($result);

/*
 php unique.php
array(3) {
    [0] =>
        array(2) {
            [0] =>
                string(3) "abc"
            [1] =>
                string(3) "def"
        }
    [1] =>
        array(2) {
            [0] =>
                string(3) "ghi"
            [1] =>
                string(3) "jkl"
        }
    [2] =>
        array(2) {
              [0] =>
                  string(3) "mno"
              [1] =>
                  string(3) "pql"
        }
}

* /

если вам нужно удалить дубликаты на определенных ключах, таких как идентификатор mysqli, вот простая функция

function search_array_compact($data,$key){
    $compact = [];
    foreach($data as $row){
        if (!in_array($row[$key],$compact)){
            $compact[] = $row;
        }
    }
    return $compact;
}

Бонусные очки Вы можете передать массив ключей и добавить внешний foreach, но каждый дополнительный ключ будет в 2 раза медленнее.

Если у вас есть такой массив

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => b
),
[3] => array
(
    [subject] => d
    [object] => c
),
[4] => array
(
    [subject] => c
    [object] => a
),
[5] => array
(
    [subject] => c
    [object] => d
)
)

и вы хотите получить такие массивы:

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => c
)
)

или же

data = array
(
[0] => array
(
    [subject] => d
    [object] => b
),
[1] => array
(
    [subject] => c
    [object] => a
),
[2] => array
(
    [subject] => c
    [object] => d
)
)

следующий код может помочь

    $data1 = array();
    $data1 = $data;
    for($q=0;$q<count($data);$q++)
    {
            for($p=0;$p<count($data1);$p++)
            {
                    if (($data[$q]["subject"] == $data1[$p]["object"]) && ($data[$q]["object"] == $data1[$p]["subject"]))
                    {
                            $data1[$p]["subject"] = $data[$q]["subject"];
                            $data1[$p]["object"] = $data[$q]["object"];
                    }
            }
    }
    $data1 = array_values(array_map("unserialize", array_unique(array_map("serialize", $data1))));
    $data = $data1;

Я много думал над этой проблемой и решил, что оптимальное решение должно соответствовать двум правилам.

  1. Для масштабируемости измените массив на месте; без копирования в новый массив
  2. Для производительности каждое сравнение следует производить только один раз.

Имея это в виду и учитывая все причуды PHP, ниже представлено решение, которое я придумал. В отличие от некоторых других ответов, он может удалять элементы на основе любого ключа (ов), который вы хотите. Ожидается, что входной массив будет числовыми клавишами.

$count_array = count($input);
for ($i = 0; $i < $count_array; $i++) {
    if (isset($input[$i])) {
        for ($j = $i+1; $j < $count_array; $j++) {
            if (isset($input[$j])) {
                //this is where you do your comparison for dupes
                if ($input[$i]['checksum'] == $input[$j]['checksum']) {
                    unset($input[$j]);
                }
            }
        }
    }
}

Единственный недостаток состоит в том, что ключи не в порядке после завершения итерации. Это не проблема, если впоследствии вы будете использовать только циклы foreach, но если вам нужно использовать цикл for, вы можете поместить $input = array_values($input); после вышеуказанного, чтобы перенумеровать ключи.

Просто используйте опцию SORT_REGULAR в качестве второго параметра.

$uniqueArray = array_unique($array, SORT_REGULAR);

SORT_REGULAR работает только в PHP 7, потому что в PHP 5 есть ошибка (хотя @ r3wt верен согласно документации), см. Мой комментарий в ответе на запускаемый пример stackoverflow.com/questions/307674/…

Zack Morris 21.09.2016 04:42

Зачем ты это добавляешь? Это то же самое, что и этот ответ, который старше вашего более чем на год: stackoverflow.com/a/18373723/870729

random_user_name 14.04.2017 23:27

Поскольку люди говорят, что array_unique() очень медленный, вот фрагмент, который я использую для одноуровневого многомерного массива.

$serialized_array = array_map("serialize", $input);

foreach ($serialized_array as $key => $val) {
     $result[$val] = true;
}

$output = array_map("unserialize", (array_keys($result)));

Ссылка на примечание первого пользователя о array_unique()страница функций в php.net

Анудж, не могли бы вы отредактировать свой ответ? Есть ошибка. Должен закончиться $output = array_map('unserialize', array_keys($result));

keyboardSmasher 16.05.2015 18:18

@keyboardSmasher благодарим вас за ваш вклад. Я внес изменения, и теперь все работает. :)

Anuj 22.05.2015 16:07

если у вас есть такой массив:

(пользователи - это имя массива)

Array=>
 [0] => (array)
   'user' => 'john'
   'age' => '23'
 [1] => (array)
  'user' => 'jane'
  'age' => '20'
 [2]=> (array)
  'user' => 'john'
  'age' => '23'

и вы хотите удалить дубликаты ... тогда:

$serialized = array();
for ($i=0; $i < sizeof($users); $i++) { 
  $test = in_array($users['user'], $serialized);
    if ($test == false) {
      $serialized[] = $users['user'];
    }
 }

может быть решением: P

Если «удалить дубликаты» означает «удалить дубликаты, но оставить один там», решением может быть сначала применить array_unique(...) к «столбцу идентификатора», а затем удалить из исходного массива все ключи, которые были удалены из столбца. множество:

$array = [
    [
        'id' => '123',
        'foo' => 'aaa',
        'bar' => 'bbb'
    ],
    [
        'id' => '123',
        'foo' => 'ccc',
        'bar' => 'ddd'
    ],
    [
        'id' => '567',
        'foo' => 'eee',
        'bar' => 'fff'
    ]
];

$ids = array_column($array, 'id');
$ids = array_unique($ids);
$array = array_filter($array, function ($key, $value) use ($ids) {
    return in_array($value, array_keys($ids));
}, ARRAY_FILTER_USE_BOTH);

Результат:

Array
(
    [0] => Array
        (
            [id] => 123
            [foo] => aaa
            [bar] => bbb
        )

    [2] => Array
        (
            [id] => 567
            [foo] => eee
            [bar] => fff
        )

)

Многие спрашивали меня, как сделать уникальный многомерный массив. Я взял ссылку из вашего комментария, и это мне помогает.

Прежде всего, спасибо @jeromegamez @daveilers за ваше решение. Но каждый раз, когда я отвечал, меня спрашивали, как работают эти «сериализация» и «десериализация». Вот почему я хочу поделиться с вами причиной этого, чтобы это помогло большему количеству людей понять концепцию, лежащую в основе этого.

Я объясняю, почему мы используем «сериализацию» и «десериализацию» поэтапно:

Шаг 1. Преобразуйте многомерный массив в одномерный массив

Чтобы преобразовать многомерный массив в одномерный массив, сначала сгенерируйте представление потока байтов всех элементов (включая вложенные массивы) внутри массива. Функция serialize () может генерировать представление значения в виде потока байтов. Чтобы сгенерировать представление потока байтов для всех элементов, вызовите функцию serialize () внутри функции array_map () как функцию обратного вызова. Результатом будет одномерный массив независимо от того, сколько уровней имеет многомерный массив.

Шаг 2. Сделайте ценности уникальными

Чтобы сделать этот одномерный массив уникальным, используйте функцию array_unique ().

Шаг 3: преобразовать его в многомерный массив

Хотя теперь массив уникален, значения выглядят как представление байтового потока. Чтобы вернуть его обратно в многомерный массив, используйте функцию unserialize ().

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

Еще раз спасибо за все это.

Очень простой и логичный способ Уникального многомерного массива заключается в следующем:

Если у вас есть такой массив:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value1
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value4
        )
)

используйте foreach, чтобы решить эту проблему:

foreach($array as $k=>$v){
    $unique=array_unique($v);
    $array[$k]=$unique;
}

это даст вам следующий результат:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
            [4] => Value4
        )
)

и если вы хотите изменить порядок клавиш,

foreach($array as $k=>$v){
    $unique= array_values(array_unique($v));
    $array[$k]=$unique;
}

Эта операция даст вам такие упорядоченные ключевые значения:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
            [3] => Value4
        )
)

Надеюсь, это все прояснит.

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => john
        )

    [1] => Array
        (
            [id] => 2
            [name] => smith
        )

    [2] => Array
        (
            [id] => 3
            [name] => john
        )

    [3] => Array
        (
            [id] => 4
            [name] => robert
        )

)

$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);

Это удалит повторяющиеся имена из массива. уникальный по ключу

Убедитесь, что ключи $array начинаются с «0». Возможно, ключи $array начинаются с другого номера, если $array является результатом предшествующей манипуляции с массивом. Используйте array_values, чтобы сбросить ключи обратно на "0"

stevevance 28.05.2020 21:19

Простое решение:

array_unique($array, SORT_REGULAR)

На основании ответа, помеченного как правильный, добавляю свой ответ. Небольшой код добавлен только для сброса индексов -

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));

Я пробовал это, чтобы удалить дубликаты.

$array = array_map("unserialize", array_unique(array_map("serialize", $array)));

Другие вопросы по теме